Add the concept of firmware 'branches'

This allows a device to identify with different streams, for instance a Lenovo
laptop could have a coreboot firmware or a AMI firmware. The GUIDs would be the
same, but switching firmware would only be done rarely and very carefully.

Another example would be switching the Broadcom BCM57xx nework adaptors from the
vendor nonfree firmware with a signed PXE image, to the free software reverse
engineered driver with no PXE support (and thus no signed DXE) at all.

It is expected firmware would have additional metadata something like this:

    ...
    <branch>sdcc</branch>
    <description>
      <p>
        This is an alternate firmware built by the community using only free
        software tools.
      </p>
    </description>
    <requires>
      <id compare="ge" version="1.5.0">org.freedesktop.fwupd</id>
      <client>switch-branch</client>
    </requires>
    ...

Additionally, alternate branch firmware will not be returned for clients not
setting the FWUPD_FEATURE_FLAG_SWITCH_BRANCH before the GetReleases request.
This commit is contained in:
Richard Hughes
2020-09-25 20:59:28 +01:00
parent f8fb2dc436
commit 460c4b75fe
16 changed files with 381 additions and 6 deletions
+2 -1
View File
@@ -26,6 +26,7 @@ _fwupdmgr_cmd_list=(
'report-history'
'security'
'set-approved-firmware'
'switch-branch'
'unlock'
'unblock-firmware'
'update'
@@ -98,7 +99,7 @@ _fwupdmgr()
esac
case $command in
activate|clear-results|downgrade|get-releases|get-results|unlock|verify|verify-update|get-updates)
activate|clear-results|downgrade|get-releases|get-results|unlock|verify|verify-update|get-updates|switch-branch)
if [[ "$prev" = "$command" ]]; then
_show_device_ids
else
+1
View File
@@ -53,6 +53,7 @@ complete -c fwupdmgr -n '__fish_use_subcommand' -x -a refresh -d 'Refresh metada
complete -c fwupdmgr -n '__fish_use_subcommand' -x -a reinstall -d 'Reinstall current firmware on the device.'
complete -c fwupdmgr -n '__fish_use_subcommand' -x -a report-history -d 'Share firmware history with the developers'
complete -c fwupdmgr -n '__fish_use_subcommand' -x -a set-approved-firmware -d 'Sets the list of approved firmware.'
complete -c fwupdmgr -n '__fish_use_subcommand' -x -a switch-branch -d 'Switch the firmware branch on the device.'
complete -c fwupdmgr -n '__fish_use_subcommand' -x -a unlock -d 'Unlocks the device for firmware access'
complete -c fwupdmgr -n '__fish_use_subcommand' -x -a update -d 'Updates all firmware to latest versions available'
complete -c fwupdmgr -n '__fish_use_subcommand' -x -a verify -d 'Checks cryptographic hash matches firmware'
+52 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2015-2017 Richard Hughes <richard@hughsie.com>
* Copyright (C) 2015-2020 Richard Hughes <richard@hughsie.com>
*
* SPDX-License-Identifier: LGPL-2.1+
*/
@@ -39,6 +39,7 @@ typedef struct {
gchar *name;
gchar *serial;
gchar *summary;
gchar *branch;
gchar *description;
gchar *vendor;
gchar *vendor_id;
@@ -172,6 +173,42 @@ fwupd_device_set_summary (FwupdDevice *device, const gchar *summary)
priv->summary = g_strdup (summary);
}
/**
* fwupd_device_get_branch:
* @device: A #FwupdDevice
*
* Gets the current device branch.
*
* Returns: the device branch, or %NULL if unset
*
* Since: 1.5.0
**/
const gchar *
fwupd_device_get_branch (FwupdDevice *device)
{
FwupdDevicePrivate *priv = GET_PRIVATE (device);
g_return_val_if_fail (FWUPD_IS_DEVICE (device), NULL);
return priv->branch;
}
/**
* fwupd_device_set_branch:
* @device: A #FwupdDevice
* @branch: the device one line branch
*
* Sets the current device branch.
*
* Since: 1.5.0
**/
void
fwupd_device_set_branch (FwupdDevice *device, const gchar *branch)
{
FwupdDevicePrivate *priv = GET_PRIVATE (device);
g_return_if_fail (FWUPD_IS_DEVICE (device));
g_free (priv->branch);
priv->branch = g_strdup (branch);
}
/**
* fwupd_device_get_serial:
* @device: A #FwupdDevice
@@ -1189,6 +1226,8 @@ fwupd_device_incorporate (FwupdDevice *self, FwupdDevice *donor)
fwupd_device_set_serial (self, priv_donor->serial);
if (priv->summary == NULL)
fwupd_device_set_summary (self, priv_donor->summary);
if (priv->branch == NULL)
fwupd_device_set_branch (self, priv_donor->branch);
if (priv->vendor == NULL)
fwupd_device_set_vendor (self, priv_donor->vendor);
if (priv->vendor_id == NULL)
@@ -1324,6 +1363,11 @@ fwupd_device_to_variant_full (FwupdDevice *device, FwupdDeviceFlags flags)
FWUPD_RESULT_KEY_SUMMARY,
g_variant_new_string (priv->summary));
}
if (priv->branch != NULL) {
g_variant_builder_add (&builder, "{sv}",
FWUPD_RESULT_KEY_BRANCH,
g_variant_new_string (priv->branch));
}
if (priv->checksums->len > 0) {
g_autoptr(GString) str = g_string_new ("");
for (guint i = 0; i < priv->checksums->len; i++) {
@@ -1536,6 +1580,10 @@ fwupd_device_from_key_value (FwupdDevice *device, const gchar *key, GVariant *va
fwupd_device_set_summary (device, g_variant_get_string (value, NULL));
return;
}
if (g_strcmp0 (key, FWUPD_RESULT_KEY_BRANCH) == 0) {
fwupd_device_set_branch (device, g_variant_get_string (value, NULL));
return;
}
if (g_strcmp0 (key, FWUPD_RESULT_KEY_DESCRIPTION) == 0) {
fwupd_device_set_description (device, g_variant_get_string (value, NULL));
return;
@@ -2036,6 +2084,7 @@ fwupd_device_to_json (FwupdDevice *device, JsonBuilder *builder)
fwupd_device_json_add_string (builder, FWUPD_RESULT_KEY_SERIAL, priv->serial);
fwupd_device_json_add_string (builder, FWUPD_RESULT_KEY_SUMMARY, priv->summary);
fwupd_device_json_add_string (builder, FWUPD_RESULT_KEY_DESCRIPTION, priv->description);
fwupd_device_json_add_string (builder, FWUPD_RESULT_KEY_BRANCH, priv->branch);
fwupd_device_json_add_string (builder, FWUPD_RESULT_KEY_PLUGIN, priv->plugin);
fwupd_device_json_add_string (builder, FWUPD_RESULT_KEY_PROTOCOL, priv->protocol);
if (priv->flags != FWUPD_DEVICE_FLAG_NONE) {
@@ -2172,6 +2221,7 @@ fwupd_device_to_string (FwupdDevice *device)
fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_SERIAL, priv->serial);
fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_SUMMARY, priv->summary);
fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_DESCRIPTION, priv->description);
fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_BRANCH, priv->branch);
fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_PLUGIN, priv->plugin);
fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_PROTOCOL, priv->protocol);
fwupd_pad_kv_dfl (str, FWUPD_RESULT_KEY_FLAGS, priv->flags);
@@ -2343,6 +2393,7 @@ fwupd_device_finalize (GObject *object)
g_free (priv->name);
g_free (priv->serial);
g_free (priv->summary);
g_free (priv->branch);
g_free (priv->vendor);
g_free (priv->vendor_id);
g_free (priv->plugin);
+4 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2015-2017 Richard Hughes <richard@hughsie.com>
* Copyright (C) 2015-2020 Richard Hughes <richard@hughsie.com>
*
* SPDX-License-Identifier: LGPL-2.1+
*/
@@ -51,6 +51,9 @@ void fwupd_device_set_serial (FwupdDevice *device,
const gchar *fwupd_device_get_summary (FwupdDevice *device);
void fwupd_device_set_summary (FwupdDevice *device,
const gchar *summary);
const gchar *fwupd_device_get_branch (FwupdDevice *device);
void fwupd_device_set_branch (FwupdDevice *device,
const gchar *branch);
const gchar *fwupd_device_get_description (FwupdDevice *device);
void fwupd_device_set_description (FwupdDevice *device,
const gchar *description);
+2 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2016-2018 Richard Hughes <richard@hughsie.com>
* Copyright (C) 2016-2020 Richard Hughes <richard@hughsie.com>
*
* SPDX-License-Identifier: LGPL-2.1+
*/
@@ -45,6 +45,7 @@ G_BEGIN_DECLS
#define FWUPD_RESULT_KEY_SIZE "Size" /* t */
#define FWUPD_RESULT_KEY_STATUS "Status" /* u */
#define FWUPD_RESULT_KEY_SUMMARY "Summary" /* s */
#define FWUPD_RESULT_KEY_BRANCH "Branch" /* s */
#define FWUPD_RESULT_KEY_TRUST_FLAGS "TrustFlags" /* t */
#define FWUPD_RESULT_KEY_UPDATE_MESSAGE "UpdateMessage" /* s */
#define FWUPD_RESULT_KEY_UPDATE_IMAGE "UpdateImage" /* s */
+12
View File
@@ -197,6 +197,8 @@ fwupd_device_flag_to_string (FwupdDeviceFlags device_flag)
return "updatable-hidden";
if (device_flag == FWUPD_DEVICE_FLAG_SKIPS_RESTART)
return "skips-restart";
if (device_flag == FWUPD_DEVICE_FLAG_HAS_MULTIPLE_BRANCHES)
return "has-multiple-branches";
if (device_flag == FWUPD_DEVICE_FLAG_UNKNOWN)
return "unknown";
return NULL;
@@ -295,6 +297,8 @@ fwupd_device_flag_from_string (const gchar *device_flag)
return FWUPD_DEVICE_FLAG_UPDATABLE_HIDDEN;
if (g_strcmp0 (device_flag, "skips-restart") == 0)
return FWUPD_DEVICE_FLAG_SKIPS_RESTART;
if (g_strcmp0 (device_flag, "has-multiple-branches") == 0)
return FWUPD_DEVICE_FLAG_HAS_MULTIPLE_BRANCHES;
return FWUPD_DEVICE_FLAG_UNKNOWN;
}
@@ -419,6 +423,8 @@ fwupd_feature_flag_to_string (FwupdFeatureFlags feature_flag)
return "detach-action";
if (feature_flag == FWUPD_FEATURE_FLAG_UPDATE_ACTION)
return "update-action";
if (feature_flag == FWUPD_FEATURE_FLAG_SWITCH_BRANCH)
return "switch-branch";
return NULL;
}
@@ -443,6 +449,8 @@ fwupd_feature_flag_from_string (const gchar *feature_flag)
return FWUPD_FEATURE_FLAG_DETACH_ACTION;
if (g_strcmp0 (feature_flag, "update-action") == 0)
return FWUPD_FEATURE_FLAG_UPDATE_ACTION;
if (g_strcmp0 (feature_flag, "switch-branch") == 0)
return FWUPD_FEATURE_FLAG_SWITCH_BRANCH;
return FWUPD_FEATURE_FLAG_LAST;
}
@@ -521,6 +529,8 @@ fwupd_release_flag_to_string (FwupdReleaseFlags release_flag)
return "blocked-version";
if (release_flag == FWUPD_RELEASE_FLAG_BLOCKED_APPROVAL)
return "blocked-approval";
if (release_flag == FWUPD_RELEASE_FLAG_IS_ALTERNATE_BRANCH)
return "is-alternate-branch";
return NULL;
}
@@ -549,6 +559,8 @@ fwupd_release_flag_from_string (const gchar *release_flag)
return FWUPD_RELEASE_FLAG_BLOCKED_VERSION;
if (g_strcmp0 (release_flag, "blocked-approval") == 0)
return FWUPD_RELEASE_FLAG_BLOCKED_APPROVAL;
if (g_strcmp0 (release_flag, "is-alternate-branch") == 0)
return FWUPD_RELEASE_FLAG_IS_ALTERNATE_BRANCH;
return FWUPD_RELEASE_FLAG_NONE;
}
+6
View File
@@ -70,6 +70,7 @@ typedef enum {
* @FWUPD_FEATURE_FLAG_CAN_REPORT: Can upload a report of the update back to the server
* @FWUPD_FEATURE_FLAG_DETACH_ACTION: Can perform detach action, typically showing text
* @FWUPD_FEATURE_FLAG_UPDATE_ACTION: Can perform update action, typically showing text
* @FWUPD_FEATURE_FLAG_SWITCH_BRANCH: Can switch the firmware branch
*
* The flags to the feature capabilities of the front-end client.
**/
@@ -78,6 +79,7 @@ typedef enum {
FWUPD_FEATURE_FLAG_CAN_REPORT = 1 << 0, /* Since: 1.4.5 */
FWUPD_FEATURE_FLAG_DETACH_ACTION = 1 << 1, /* Since: 1.4.5 */
FWUPD_FEATURE_FLAG_UPDATE_ACTION = 1 << 2, /* Since: 1.4.5 */
FWUPD_FEATURE_FLAG_SWITCH_BRANCH = 1 << 3, /* Since: 1.5.0 */
/*< private >*/
FWUPD_FEATURE_FLAG_LAST
} FwupdFeatureFlags;
@@ -124,6 +126,7 @@ typedef enum {
* @FWUPD_DEVICE_FLAG_NO_GUID_MATCHING: Force an explicit ID match when adding devices to the device list
* @FWUPD_DEVICE_FLAG_UPDATABLE_HIDDEN: Device is updatable but should not be called by the client
* @FWUPD_DEVICE_FLAG_SKIPS_RESTART: Device relies upon activation or power cycle to load firmware
* @FWUPD_DEVICE_FLAG_HAS_MULTIPLE_BRANCHES: Device supports switching to a different stream of firmware
*
* The device flags.
**/
@@ -167,6 +170,7 @@ typedef enum {
#define FWUPD_DEVICE_FLAG_NO_GUID_MATCHING (1llu << 36) /* Since: 1.4.1 */
#define FWUPD_DEVICE_FLAG_UPDATABLE_HIDDEN (1llu << 37) /* Since: 1.4.1 */
#define FWUPD_DEVICE_FLAG_SKIPS_RESTART (1llu << 38) /* Since: 1.5.0 */
#define FWUPD_DEVICE_FLAG_HAS_MULTIPLE_BRANCHES (1llu << 39) /* Since: 1.5.0 */
#define FWUPD_DEVICE_FLAG_UNKNOWN G_MAXUINT64 /* Since: 0.7.3 */
typedef guint64 FwupdDeviceFlags;
@@ -179,6 +183,7 @@ typedef guint64 FwupdDeviceFlags;
* @FWUPD_RELEASE_FLAG_IS_DOWNGRADE: Is older than the device version
* @FWUPD_RELEASE_FLAG_BLOCKED_VERSION: Blocked as below device version-lowest
* @FWUPD_RELEASE_FLAG_BLOCKED_APPROVAL: Blocked as release not approved
* @FWUPD_RELEASE_FLAG_IS_ALTERNATE_BRANCH: Is an alternate branch of firmware
*
* The release flags.
**/
@@ -189,6 +194,7 @@ typedef guint64 FwupdDeviceFlags;
#define FWUPD_RELEASE_FLAG_IS_DOWNGRADE (1u << 3) /* Since: 1.2.6 */
#define FWUPD_RELEASE_FLAG_BLOCKED_VERSION (1u << 4) /* Since: 1.2.6 */
#define FWUPD_RELEASE_FLAG_BLOCKED_APPROVAL (1u << 5) /* Since: 1.2.6 */
#define FWUPD_RELEASE_FLAG_IS_ALTERNATE_BRANCH (1u << 6) /* Since: 1.5.0 */
#define FWUPD_RELEASE_FLAG_UNKNOWN G_MAXUINT64 /* Since: 1.2.6 */
typedef guint64 FwupdReleaseFlags;
+50 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2015-2018 Richard Hughes <richard@hughsie.com>
* Copyright (C) 2015-2020 Richard Hughes <richard@hughsie.com>
*
* SPDX-License-Identifier: LGPL-2.1+
*/
@@ -46,6 +46,7 @@ typedef struct {
gchar *name;
gchar *name_variant_suffix;
gchar *summary;
gchar *branch;
gchar *uri;
gchar *vendor;
gchar *version;
@@ -934,6 +935,42 @@ fwupd_release_set_summary (FwupdRelease *release, const gchar *summary)
priv->summary = g_strdup (summary);
}
/**
* fwupd_release_get_branch:
* @release: A #FwupdRelease
*
* Gets the update branch.
*
* Returns: the alternate branch, or %NULL if unset
*
* Since: 1.5.0
**/
const gchar *
fwupd_release_get_branch (FwupdRelease *release)
{
FwupdReleasePrivate *priv = GET_PRIVATE (release);
g_return_val_if_fail (FWUPD_IS_RELEASE (release), NULL);
return priv->branch;
}
/**
* fwupd_release_set_branch:
* @release: A #FwupdRelease
* @branch: the update one line branch
*
* Sets the alternate branch.
*
* Since: 1.5.0
**/
void
fwupd_release_set_branch (FwupdRelease *release, const gchar *branch)
{
FwupdReleasePrivate *priv = GET_PRIVATE (release);
g_return_if_fail (FWUPD_IS_RELEASE (release));
g_free (priv->branch);
priv->branch = g_strdup (branch);
}
/**
* fwupd_release_get_vendor:
* @release: A #FwupdRelease
@@ -1354,6 +1391,11 @@ fwupd_release_to_variant (FwupdRelease *release)
FWUPD_RESULT_KEY_SUMMARY,
g_variant_new_string (priv->summary));
}
if (priv->branch != NULL) {
g_variant_builder_add (&builder, "{sv}",
FWUPD_RESULT_KEY_BRANCH,
g_variant_new_string (priv->branch));
}
if (priv->description != NULL) {
g_variant_builder_add (&builder, "{sv}",
FWUPD_RESULT_KEY_DESCRIPTION,
@@ -1492,6 +1534,10 @@ fwupd_release_from_key_value (FwupdRelease *release, const gchar *key, GVariant
fwupd_release_set_summary (release, g_variant_get_string (value, NULL));
return;
}
if (g_strcmp0 (key, FWUPD_RESULT_KEY_BRANCH) == 0) {
fwupd_release_set_branch (release, g_variant_get_string (value, NULL));
return;
}
if (g_strcmp0 (key, FWUPD_RESULT_KEY_DESCRIPTION) == 0) {
fwupd_release_set_description (release, g_variant_get_string (value, NULL));
return;
@@ -1675,6 +1721,7 @@ fwupd_release_to_json (FwupdRelease *release, JsonBuilder *builder)
fwupd_release_json_add_string (builder, FWUPD_RESULT_KEY_REMOTE_ID, priv->remote_id);
fwupd_release_json_add_string (builder, FWUPD_RESULT_KEY_SUMMARY, priv->summary);
fwupd_release_json_add_string (builder, FWUPD_RESULT_KEY_DESCRIPTION, priv->description);
fwupd_release_json_add_string (builder, FWUPD_RESULT_KEY_BRANCH, priv->branch);
fwupd_release_json_add_string (builder, FWUPD_RESULT_KEY_VERSION, priv->version);
fwupd_release_json_add_string (builder, FWUPD_RESULT_KEY_FILENAME, priv->filename);
fwupd_release_json_add_string (builder, FWUPD_RESULT_KEY_PROTOCOL, priv->protocol);
@@ -1764,6 +1811,7 @@ fwupd_release_to_string (FwupdRelease *release)
fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_REMOTE_ID, priv->remote_id);
fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_SUMMARY, priv->summary);
fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_DESCRIPTION, priv->description);
fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_BRANCH, priv->branch);
fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_VERSION, priv->version);
fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_FILENAME, priv->filename);
fwupd_pad_kv_str (str, FWUPD_RESULT_KEY_PROTOCOL, priv->protocol);
@@ -1844,6 +1892,7 @@ fwupd_release_finalize (GObject *object)
g_free (priv->name);
g_free (priv->name_variant_suffix);
g_free (priv->summary);
g_free (priv->branch);
g_free (priv->uri);
g_free (priv->homepage);
g_free (priv->details_url);
+4 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2015-2018 Richard Hughes <richard@hughsie.com>
* Copyright (C) 2015-2020 Richard Hughes <richard@hughsie.com>
*
* SPDX-License-Identifier: LGPL-2.1+
*/
@@ -90,6 +90,9 @@ void fwupd_release_set_name_variant_suffix (FwupdRelease *release,
const gchar *fwupd_release_get_summary (FwupdRelease *release);
void fwupd_release_set_summary (FwupdRelease *release,
const gchar *summary);
const gchar *fwupd_release_get_branch (FwupdRelease *release);
void fwupd_release_set_branch (FwupdRelease *release,
const gchar *branch);
const gchar *fwupd_release_get_description (FwupdRelease *release);
void fwupd_release_set_description (FwupdRelease *release,
const gchar *description);
+4
View File
@@ -552,6 +552,10 @@ LIBFWUPD_1.5.0 {
fwupd_client_verify_finish;
fwupd_client_verify_update_async;
fwupd_client_verify_update_finish;
fwupd_device_get_branch;
fwupd_device_set_branch;
fwupd_release_get_branch;
fwupd_release_set_branch;
fwupd_remote_get_automatic_security_reports;
fwupd_remote_get_security_report_uri;
fwupd_security_attr_add_flag;
+4
View File
@@ -973,6 +973,10 @@ fu_device_set_quirk_kv (FuDevice *self,
fu_device_set_summary (self, value);
return TRUE;
}
if (g_strcmp0 (key, FU_QUIRKS_BRANCH) == 0) {
fu_device_set_branch (self, value);
return TRUE;
}
if (g_strcmp0 (key, FU_QUIRKS_VENDOR) == 0) {
fu_device_set_vendor (self, value);
return TRUE;
+2
View File
@@ -132,6 +132,7 @@ FuDevice *fu_device_new (void);
#define fu_device_set_plugin(d,v) fwupd_device_set_plugin(FWUPD_DEVICE(d),v)
#define fu_device_set_serial(d,v) fwupd_device_set_serial(FWUPD_DEVICE(d),v)
#define fu_device_set_summary(d,v) fwupd_device_set_summary(FWUPD_DEVICE(d),v)
#define fu_device_set_branch(d,v) fwupd_device_set_branch(FWUPD_DEVICE(d),v)
#define fu_device_set_update_message(d,v) fwupd_device_set_update_message(FWUPD_DEVICE(d),v)
#define fu_device_set_update_image(d,v) fwupd_device_set_update_image(FWUPD_DEVICE(d),v)
#define fu_device_set_update_error(d,v) fwupd_device_set_update_error(FWUPD_DEVICE(d),v)
@@ -154,6 +155,7 @@ FuDevice *fu_device_new (void);
#define fu_device_get_name(d) fwupd_device_get_name(FWUPD_DEVICE(d))
#define fu_device_get_serial(d) fwupd_device_get_serial(FWUPD_DEVICE(d))
#define fu_device_get_summary(d) fwupd_device_get_summary(FWUPD_DEVICE(d))
#define fu_device_get_branch(d) fwupd_device_get_branch(FWUPD_DEVICE(d))
#define fu_device_get_id(d) fwupd_device_get_id(FWUPD_DEVICE(d))
#define fu_device_get_plugin(d) fwupd_device_get_plugin(FWUPD_DEVICE(d))
#define fu_device_get_update_error(d) fwupd_device_get_update_error(FWUPD_DEVICE(d))
+1
View File
@@ -48,6 +48,7 @@ gboolean fu_quirks_lookup_by_id_iter (FuQuirks *self,
#define FU_QUIRKS_SUMMARY "Summary"
#define FU_QUIRKS_ICON "Icon"
#define FU_QUIRKS_NAME "Name"
#define FU_QUIRKS_BRANCH "Branch"
#define FU_QUIRKS_GUID "Guid"
#define FU_QUIRKS_COUNTERPART_GUID "CounterpartGuid"
#define FU_QUIRKS_PARENT_GUID "ParentGuid"
+60
View File
@@ -356,6 +356,9 @@ fu_engine_set_release_from_appstream (FuEngine *self,
tmp = xb_node_query_text (component, "summary", NULL);
if (tmp != NULL)
fwupd_release_set_summary (rel, tmp);
tmp = xb_node_query_text (component, "branch", NULL);
if (tmp != NULL)
fwupd_release_set_branch (rel, tmp);
tmp = xb_node_query_text (component, "developer_name", NULL);
if (tmp != NULL)
fwupd_release_set_vendor (rel, tmp);
@@ -4164,6 +4167,14 @@ fu_engine_sort_releases_cb (gconstpointer a, gconstpointer b, gpointer user_data
FuDevice *device = FU_DEVICE (user_data);
FwupdRelease *rel_a = FWUPD_RELEASE (*((FwupdRelease **) a));
FwupdRelease *rel_b = FWUPD_RELEASE (*((FwupdRelease **) b));
gint rc;
/* first by branch */
rc = g_strcmp0 (fwupd_release_get_branch (rel_b), fwupd_release_get_branch (rel_a));
if (rc != 0)
return rc;
/* then by version */
return fu_common_vercmp_full (fwupd_release_get_version (rel_b),
fwupd_release_get_version (rel_a),
fu_device_get_version_format (device));
@@ -4206,6 +4217,7 @@ fu_engine_add_releases_for_device_component (FuEngine *self,
GPtrArray *releases,
GError **error)
{
FwupdFeatureFlags feature_flags;
FwupdVersionFormat fmt = fu_device_get_version_format (device);
g_autoptr(GError) error_local = NULL;
g_autoptr(FuInstallTask) task = fu_install_task_new (device, component);
@@ -4228,6 +4240,7 @@ fu_engine_add_releases_for_device_component (FuEngine *self,
g_propagate_error (error, g_steal_pointer (&error_local));
return FALSE;
}
feature_flags = fu_engine_request_get_feature_flags (request);
for (guint i = 0; i < releases_tmp->len; i++) {
XbNode *release = g_ptr_array_index (releases_tmp, i);
const gchar *remote_id;
@@ -4261,6 +4274,18 @@ fu_engine_add_releases_for_device_component (FuEngine *self,
if (checksums->len == 0)
continue;
/* different branch */
if (g_strcmp0 (fwupd_release_get_branch (rel),
fu_device_get_branch (device)) != 0) {
if ((feature_flags & FWUPD_FEATURE_FLAG_SWITCH_BRANCH) == 0) {
g_debug ("client does not understand branches, skipping %s:%s",
fwupd_release_get_branch (rel),
fwupd_release_get_version (rel));
continue;
}
fwupd_release_add_flag (rel, FWUPD_RELEASE_FLAG_IS_ALTERNATE_BRANCH);
}
/* test for upgrade or downgrade */
vercmp = fu_common_vercmp_full (fwupd_release_get_version (rel),
fu_device_get_version (device),
@@ -4323,6 +4348,7 @@ fu_engine_get_releases_for_device (FuEngine *self,
const gchar *version;
g_autoptr(GError) error_all = NULL;
g_autoptr(GError) error_local = NULL;
g_autoptr(GPtrArray) branches = NULL;
g_autoptr(GPtrArray) components = NULL;
g_autoptr(GString) xpath = g_string_new (NULL);
@@ -4389,6 +4415,21 @@ fu_engine_get_releases_for_device (FuEngine *self,
}
}
/* are there multiple branches available */
branches = g_ptr_array_new_with_free_func (g_free);
for (guint i = 0; i < releases->len; i++) {
FwupdRelease *rel_tmp = FWUPD_RELEASE (g_ptr_array_index (releases, i));
const gchar *branch_tmp = fwupd_release_get_branch (rel_tmp);
if (branch_tmp == NULL)
branch_tmp = "default";
if (g_ptr_array_find_with_equal_func (branches, branch_tmp,
g_str_equal, NULL))
continue;
g_ptr_array_add (branches, g_strdup (branch_tmp));
}
if (branches->len > 0)
fu_device_add_flag (device, FWUPD_DEVICE_FLAG_HAS_MULTIPLE_BRANCHES);
/* return the compound error */
if (releases->len == 0) {
if (error_all != NULL) {
@@ -4518,6 +4559,16 @@ fu_engine_get_downgrades (FuEngine *self,
fu_device_get_version_lowest (device));
continue;
}
/* different branch */
if (fwupd_release_has_flag (rel_tmp, FWUPD_RELEASE_FLAG_IS_ALTERNATE_BRANCH)) {
g_debug ("ignoring release %s as branch %s, and device is %s",
fwupd_release_get_version (rel_tmp),
fwupd_release_get_branch (rel_tmp),
fu_device_get_branch (device));
continue;
}
g_ptr_array_add (releases, g_object_ref (rel_tmp));
}
if (error_str->len > 2)
@@ -4727,6 +4778,15 @@ fu_engine_get_upgrades (FuEngine *self,
continue;
}
/* different branch */
if (fwupd_release_has_flag (rel_tmp, FWUPD_RELEASE_FLAG_IS_ALTERNATE_BRANCH)) {
g_debug ("ignoring release %s as branch %s, and device is %s",
fwupd_release_get_version (rel_tmp),
fwupd_release_get_branch (rel_tmp),
fu_device_get_branch (device));
continue;
}
g_ptr_array_add (releases, g_object_ref (rel_tmp));
}
if (error_str->len > 2)
+9
View File
@@ -1073,6 +1073,10 @@ fu_util_device_flag_to_string (guint64 device_flag)
/* TRANSLATORS: a version check is required for all firmware */
return _("Device is required to install all provided releases");
}
if (device_flag == FWUPD_DEVICE_FLAG_HAS_MULTIPLE_BRANCHES) {
/* TRANSLATORS: there is more than one supplier of the firmware */
return _("Device supports switching to a different branch of firmware");
}
if (device_flag == FWUPD_DEVICE_FLAG_MD_SET_NAME) {
/* skip */
return NULL;
@@ -1337,6 +1341,11 @@ fu_util_release_to_string (FwupdRelease *rel, guint idt)
fu_common_string_append_kv (str, idt + 1, _("Remote ID"),
fwupd_release_get_remote_id (rel));
}
if (fwupd_release_get_branch (rel) != NULL) {
/* TRANSLATORS: the stream of firmware, e.g. nonfree or open-source */
fu_common_string_append_kv (str, idt + 1, _("Branch"),
fwupd_release_get_branch (rel));
}
if (fwupd_release_get_summary (rel) != NULL) {
/* TRANSLATORS: one line summary of device */
fu_common_string_append_kv (str, idt + 1, _("Summary"),
+168
View File
@@ -1868,6 +1868,167 @@ fu_util_reinstall (FuUtilPrivate *priv, gchar **values, GError **error)
return fu_util_prompt_complete (priv->completion_flags, TRUE, error);
}
static gboolean
fu_util_switch_branch_warning (FuUtilPrivate *priv,
FwupdDevice *dev,
FwupdRelease *rel,
GError **error)
{
const gchar *desc_markup = NULL;
g_autofree gchar *desc_plain = NULL;
g_autoptr(GString) desc_full = g_string_new (NULL);
/* warn the user if the vendor is different */
if (g_strcmp0 (fwupd_device_get_vendor (dev), fwupd_release_get_vendor (rel)) != 0) {
/* TRANSLATORS: %1 is the firmware vendor, %2 is the device vendor name */
g_string_append_printf (desc_full, _("The firmware from %s is not "
"supplied by %s, the hardware vendor."),
fwupd_release_get_vendor (rel),
fwupd_device_get_vendor (dev));
g_string_append (desc_full, "\n\n");
/* TRANSLATORS: %1 is the device vendor name */
g_string_append_printf (desc_full, _("Your hardware may be damaged using this firmware, "
"and installing this release may void any warranty "
"with %s."),
fwupd_device_get_vendor (dev));
g_string_append (desc_full, "\n\n");
}
/* from the <description> in the AppStream data */
desc_markup = fwupd_release_get_description (rel);
if (desc_markup == NULL)
return TRUE;
desc_plain = fu_util_convert_description (desc_markup, error);
if (desc_plain == NULL)
return FALSE;
g_string_append (desc_full, desc_plain);
/* show and ask user to confirm */
fu_util_warning_box (desc_full->str, 80);
if (!priv->assume_yes) {
/* ask for permission */
g_print ("\n%s [y|N]: ",
/* TRANSLATORS: should the branch be changed */
_("Do you understand the consequences of changing the firmware branch?"));
if (!fu_util_prompt_for_boolean (FALSE)) {
g_set_error_literal (error,
FWUPD_ERROR,
FWUPD_ERROR_NOTHING_TO_DO,
"Declined branch switch");
return FALSE;
}
}
return TRUE;
}
static gboolean
fu_util_switch_branch (FuUtilPrivate *priv, gchar **values, GError **error)
{
const gchar *remote_id;
const gchar *branch;
g_autoptr(FwupdRelease) rel = NULL;
g_autoptr(GPtrArray) rels = NULL;
g_autoptr(GPtrArray) branches = g_ptr_array_new_with_free_func (g_free);
g_autoptr(FwupdDevice) dev = NULL;
/* find the device and check it has multiple branches */
priv->filter_include |= FWUPD_DEVICE_FLAG_SUPPORTED;
dev = fu_util_get_device_or_prompt (priv, values, error);
if (dev == NULL)
return FALSE;
if (!fwupd_device_has_flag (dev, FWUPD_DEVICE_FLAG_HAS_MULTIPLE_BRANCHES)) {
g_set_error_literal (error,
FWUPD_ERROR,
FWUPD_ERROR_NOT_SUPPORTED,
"Multiple branches not available");
return FALSE;
}
/* get all releases, including the alternate branch versions */
rels = fwupd_client_get_releases (priv->client, fwupd_device_get_id (dev),
NULL, error);
if (rels == NULL)
return FALSE;
/* branch name is optional */
if (g_strv_length (values) > 1) {
branch = values[1];
if (g_strcmp0 (branch, fu_device_get_branch (dev)) == 0) {
g_set_error (error,
FWUPD_ERROR,
FWUPD_ERROR_NOT_SUPPORTED,
"Device %s is already on branch %s",
fu_device_get_name (dev),
branch);
return FALSE;
}
} else {
guint idx;
/* TRANSLATORS: get interactive prompt, where branch is the
* supplier of the firmware, e.g. "non-free" or "free" */
g_print ("%s\n", _("Choose a branch:"));
/* TRANSLATORS: this is to abort the interactive prompt */
g_print ("0.\t%s\n", _("Cancel"));
for (guint i = 0; i < branches->len; i++) {
const gchar *branch_tmp = g_ptr_array_index (branches, i);
g_print ("%u.\t%s\n", i + 1, branch_tmp);
}
idx = fu_util_prompt_for_number (branches->len);
if (idx == 0) {
g_set_error_literal (error,
FWUPD_ERROR,
FWUPD_ERROR_NOTHING_TO_DO,
"Request canceled");
return FALSE;
}
branch = g_ptr_array_index (branches, idx - 1);
}
/* the releases are ordered by version */
for (guint j = 0; j < rels->len; j++) {
FwupdRelease *rel_tmp = g_ptr_array_index (rels, j);
if (g_strcmp0 (fwupd_release_get_branch (rel_tmp), branch) == 0) {
rel = g_object_ref (rel_tmp);
break;
}
}
if (rel == NULL) {
g_set_error (error,
FWUPD_ERROR,
FWUPD_ERROR_NOT_SUPPORTED,
"No releases for branch %s",
branch);
return FALSE;
}
/* we're switching branch */
if (!fu_util_switch_branch_warning (priv, dev, rel, error))
return FALSE;
/* update the console if composite devices are also updated */
priv->current_operation = FU_UTIL_OPERATION_INSTALL;
g_signal_connect (priv->client, "device-changed",
G_CALLBACK (fu_util_update_device_changed_cb), priv);
priv->flags |= FWUPD_INSTALL_FLAG_ALLOW_REINSTALL;
if (!fu_util_update_device_with_release (priv, dev, rel, error))
return FALSE;
fu_util_display_current_message (priv);
/* send report if we're supposed to */
remote_id = fwupd_release_get_remote_id (rel);
if (!fu_util_maybe_send_reports (priv, remote_id, error))
return FALSE;
/* we don't want to ask anything */
if (priv->no_reboot_check) {
g_debug ("skipping reboot check");
return TRUE;
}
return fu_util_prompt_complete (priv->completion_flags, TRUE, error);
}
static gboolean
fu_util_activate (FuUtilPrivate *priv, gchar **values, GError **error)
{
@@ -2732,6 +2893,12 @@ main (int argc, char *argv[])
/* TRANSLATORS: command description */
_("Reinstall current firmware on the device."),
fu_util_reinstall);
fu_util_cmd_array_add (cmd_array,
"switch-branch",
"[DEVICE-ID|GUID] [BRANCH]",
/* TRANSLATORS: command description */
_("Switch the firmware branch on the device."),
fu_util_switch_branch);
fu_util_cmd_array_add (cmd_array,
"security",
NULL,
@@ -2911,6 +3078,7 @@ main (int argc, char *argv[])
if (is_interactive) {
if (!fwupd_client_set_feature_flags (priv->client,
FWUPD_FEATURE_FLAG_CAN_REPORT |
FWUPD_FEATURE_FLAG_SWITCH_BRANCH |
FWUPD_FEATURE_FLAG_UPDATE_ACTION |
FWUPD_FEATURE_FLAG_DETACH_ACTION,
priv->cancellable, &error)) {