mirror of
https://github.com/Dasharo/fwupd.git
synced 2026-03-06 14:49:39 -08:00
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:
@@ -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
|
||||
|
||||
@@ -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
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
@@ -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)) {
|
||||
|
||||
Reference in New Issue
Block a user