mirror of
https://git.proxmox.com/git/fwupd
synced 2025-08-14 00:38:14 +00:00
Add a 'report-history' command to fwupdmgr
This shares your history with a reporting server, typically the LVFS. NOTE: no data is sent without the user opting-in, and the data sent is shown to the user before upload.
This commit is contained in:
parent
b58104895d
commit
0a7bc97317
183
src/fu-util.c
183
src/fu-util.c
@ -237,6 +237,26 @@ fu_util_prompt_for_number (guint maxnum)
|
||||
return answer;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fu_util_prompt_for_boolean (gboolean def)
|
||||
{
|
||||
do {
|
||||
char buffer[4];
|
||||
if (!fgets (buffer, sizeof (buffer), stdin))
|
||||
continue;
|
||||
if (strlen (buffer) == sizeof (buffer) - 1)
|
||||
continue;
|
||||
if (g_strcmp0 (buffer, "\n") == 0)
|
||||
return def;
|
||||
buffer[0] = g_ascii_toupper (buffer[0]);
|
||||
if (g_strcmp0 (buffer, "Y\n") == 0)
|
||||
return TRUE;
|
||||
if (g_strcmp0 (buffer, "N\n") == 0)
|
||||
return FALSE;
|
||||
} while (TRUE);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static FwupdDevice *
|
||||
fu_util_prompt_for_device (FuUtilPrivate *priv, GError **error)
|
||||
{
|
||||
@ -569,6 +589,163 @@ fu_util_clear_history (FuUtilPrivate *priv, gchar **values, GError **error)
|
||||
return fu_history_remove_all (history, error);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fu_util_report_history_for_uri (FuUtilPrivate *priv,
|
||||
const gchar *report_uri,
|
||||
GPtrArray *devices,
|
||||
GError **error)
|
||||
{
|
||||
guint status_code;
|
||||
g_autofree gchar *data = NULL;
|
||||
g_autoptr(SoupMessage) msg = NULL;
|
||||
|
||||
/* convert to JSON */
|
||||
data = fwupd_build_history_report_json (devices, error);
|
||||
if (data == NULL)
|
||||
return FALSE;
|
||||
|
||||
/* ask for permission */
|
||||
fu_util_print_data (_("Target"), report_uri);
|
||||
fu_util_print_data (_("Payload"), data);
|
||||
g_print ("%s [Y|n]: ", _("Proceed with upload?"));
|
||||
if (!fu_util_prompt_for_boolean (TRUE)) {
|
||||
g_set_error_literal (error,
|
||||
FWUPD_ERROR,
|
||||
FWUPD_ERROR_PERMISSION_DENIED,
|
||||
"User declined action");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* POST request */
|
||||
msg = soup_message_new (SOUP_METHOD_POST, report_uri);
|
||||
soup_message_set_request (msg, "application/json; charset=utf-8",
|
||||
SOUP_MEMORY_COPY, data, strlen (data));
|
||||
status_code = soup_session_send_message (priv->soup_session, msg);
|
||||
g_debug ("server returned: %s", msg->response_body->data);
|
||||
if (!SOUP_STATUS_IS_SUCCESSFUL (status_code)) {
|
||||
g_set_error (error,
|
||||
FWUPD_ERROR,
|
||||
FWUPD_ERROR_INVALID_FILE,
|
||||
"Failed to upload to %s: %s",
|
||||
report_uri, soup_status_get_phrase (status_code));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fu_util_report_history (FuUtilPrivate *priv, gchar **values, GError **error)
|
||||
{
|
||||
g_autoptr(GHashTable) remote_id_uri_map = NULL;
|
||||
g_autoptr(GHashTable) report_map = NULL;
|
||||
g_autoptr(GList) uris = NULL;
|
||||
g_autoptr(GPtrArray) devices = NULL;
|
||||
g_autoptr(GPtrArray) remotes = NULL;
|
||||
|
||||
/* set up networking */
|
||||
if (!fu_util_setup_networking (priv, error))
|
||||
return FALSE;
|
||||
|
||||
/* create a map of RemoteID to RemoteURI */
|
||||
remotes = fwupd_client_get_remotes (priv->client, NULL, error);
|
||||
if (remotes == NULL)
|
||||
return FALSE;
|
||||
remote_id_uri_map = g_hash_table_new (g_str_hash, g_str_equal);
|
||||
for (guint i = 0; i < remotes->len; i++) {
|
||||
FwupdRemote *remote = g_ptr_array_index (remotes, i);
|
||||
if (fwupd_remote_get_id (remote) == NULL)
|
||||
continue;
|
||||
if (fwupd_remote_get_report_uri (remote) == NULL)
|
||||
continue;
|
||||
g_debug ("adding %s for %s",
|
||||
fwupd_remote_get_report_uri (remote),
|
||||
fwupd_remote_get_id (remote));
|
||||
g_hash_table_insert (remote_id_uri_map,
|
||||
(gpointer) fwupd_remote_get_id (remote),
|
||||
(gpointer) fwupd_remote_get_report_uri (remote));
|
||||
}
|
||||
|
||||
/* get all devices from the history database, then filter them,
|
||||
* adding to a hash map of report-ids */
|
||||
devices = fwupd_client_get_history (priv->client, NULL, error);
|
||||
if (devices == NULL)
|
||||
return FALSE;
|
||||
report_map = g_hash_table_new_full (g_str_hash, g_str_equal,
|
||||
g_free, (GDestroyNotify) g_ptr_array_unref);
|
||||
for (guint i = 0; i < devices->len; i++) {
|
||||
FwupdDevice *dev = g_ptr_array_index (devices, i);
|
||||
FwupdRelease *rel = fwupd_device_get_release_default (dev);
|
||||
const gchar *remote_id;
|
||||
const gchar *remote_uri;
|
||||
GPtrArray *devices_tmp;
|
||||
|
||||
/* filter, if not forcing */
|
||||
if ((priv->flags & FWUPD_INSTALL_FLAG_FORCE) == 0) {
|
||||
if (fwupd_device_has_flag (dev, FWUPD_DEVICE_FLAG_REPORTED))
|
||||
continue;
|
||||
if (!fwupd_device_has_flag (dev, FWUPD_DEVICE_FLAG_SUPPORTED))
|
||||
continue;
|
||||
}
|
||||
|
||||
/* find the RemoteURI to use for the device */
|
||||
remote_id = fwupd_release_get_remote_id (rel);
|
||||
if (remote_id == NULL) {
|
||||
g_debug ("%s has no RemoteID", fwupd_device_get_id (dev));
|
||||
continue;
|
||||
}
|
||||
remote_uri = g_hash_table_lookup (remote_id_uri_map, remote_id);
|
||||
if (remote_uri == NULL) {
|
||||
g_debug ("%s has no RemoteURI", remote_id);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* add this to the hash map */
|
||||
devices_tmp = g_hash_table_lookup (report_map, remote_uri);
|
||||
if (devices_tmp == NULL) {
|
||||
devices_tmp = g_ptr_array_new ();
|
||||
g_hash_table_insert (report_map, g_strdup (remote_uri), devices_tmp);
|
||||
}
|
||||
g_debug ("using %s for %s", remote_uri, fwupd_device_get_id (dev));
|
||||
g_ptr_array_add (devices_tmp, dev);
|
||||
}
|
||||
|
||||
/* nothing to report */
|
||||
if (g_hash_table_size (report_map) == 0) {
|
||||
g_set_error_literal (error,
|
||||
FWUPD_ERROR,
|
||||
FWUPD_ERROR_NOT_SUPPORTED,
|
||||
"No reports require uploading");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* process each uri */
|
||||
uris = g_hash_table_get_keys (report_map);
|
||||
for (GList *l = uris; l != NULL; l = l->next) {
|
||||
const gchar *uri = l->data;
|
||||
GPtrArray *devices_tmp = g_hash_table_lookup (report_map, uri);
|
||||
if (!fu_util_report_history_for_uri (priv, uri, devices_tmp, error))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* mark each device as reported */
|
||||
for (guint i = 0; i < devices->len; i++) {
|
||||
FwupdDevice *dev = g_ptr_array_index (devices, i);
|
||||
if (fwupd_device_has_flag (dev, FWUPD_DEVICE_FLAG_REPORTED))
|
||||
continue;
|
||||
if (!fwupd_device_has_flag (dev, FWUPD_DEVICE_FLAG_SUPPORTED))
|
||||
continue;
|
||||
g_debug ("setting flag on %s", fwupd_device_get_id (dev));
|
||||
if (!fwupd_client_modify_device (priv->client,
|
||||
fwupd_device_get_id (dev),
|
||||
"Flags", "reported",
|
||||
NULL, error))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fu_util_get_history (FuUtilPrivate *priv, gchar **values, GError **error)
|
||||
{
|
||||
@ -1716,6 +1893,12 @@ main (int argc, char *argv[])
|
||||
/* TRANSLATORS: command description */
|
||||
_("Erase all firmware update history"),
|
||||
fu_util_clear_history);
|
||||
fu_util_add (priv->cmd_array,
|
||||
"report-history",
|
||||
NULL,
|
||||
/* TRANSLATORS: command description */
|
||||
_("Share firmware history with the developers"),
|
||||
fu_util_report_history);
|
||||
fu_util_add (priv->cmd_array,
|
||||
"install",
|
||||
"FILE [ID]",
|
||||
|
Loading…
Reference in New Issue
Block a user