2
* Copyright (C) 2019 Canonical Ltd
4
* This library is free software; you can redistribute it and/or
5
* modify it under the terms of the GNU Lesser General Public
6
* License as published by the Free Software Foundation; either
7
* version 2 of the License, or (at your option) any later version.
9
* This library is distributed in the hope that it will be useful,
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
* Lesser General Public License for more details.
14
* You should have received a copy of the GNU Lesser General Public
15
* License along with this library; if not, write to the
16
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor
17
* Boston, MA 02110-1301 USA.
20
#include "livepatch-utils.h"
22
#include <gio/gdesktopappinfo.h>
24
#include <json-glib/json-glib.h>
26
#define OS_RELEASE_PATH "/etc/os-release"
29
livepatch_error_quark(void)
34
q = g_quark_from_static_string("livepatch-error-quark");
42
g_autoptr(GKeyFile) keys = NULL;
43
g_autofree gchar *content = NULL;
44
g_autofree gchar *content_with_group = NULL;
45
const gchar *group = "[os-release]\n";
46
g_autoptr(GError) error = NULL;
48
if (!g_file_get_contents(OS_RELEASE_PATH, &content, NULL, &error))
50
g_warning("Failed to read '%s', error: %s",
51
OS_RELEASE_PATH, error->message);
55
content_with_group = g_strdup_printf("%s%s", group, content);
57
keys = g_key_file_new();
58
if (!g_key_file_load_from_data(keys, content_with_group, -1,
59
G_KEY_FILE_NONE, &error))
61
g_warning("Failed to parse /etc/os-release: %s", error->message);
65
return g_steal_pointer(&keys);
69
livepatch_get_status(GError **error)
71
g_autofree gchar *std_output = NULL;
72
g_autofree gchar *std_error = NULL;
73
g_autoptr(JsonParser) json_parser = NULL;
76
if (!g_spawn_command_line_sync("canonical-livepatch status --format=json",
77
&std_output, &std_error, NULL, error))
80
if (std_output == NULL || strlen(std_output) == 0)
82
if (std_error == NULL || strlen(std_error) == 0)
85
LIVEPATCH_ERROR, LIVEPATCH_ERROR_CMD_FAILED,
86
"canonical-livepatch returned an empty status.");
91
LIVEPATCH_ERROR, LIVEPATCH_ERROR_CMD_FAILED,
92
"canonical-livepatch status returned an error: %s",
99
json_parser = json_parser_new();
100
if (!json_parser_load_from_data(json_parser, std_output, -1, error))
103
root_node = json_parser_get_root(json_parser);
104
if (root_node == NULL)
107
LIVEPATCH_ERROR, LIVEPATCH_ERROR_CMD_FAILED,
108
"The output of canonical-livepatch has no json root node.");
112
return json_node_copy(root_node);
116
livepatch_get_status_node(const gchar *expr, GError **error)
118
g_autoptr(JsonNode) root = NULL;
120
root = livepatch_get_status(error);
124
return json_path_query(expr, root, error);
128
livepatch_has_settings_ui()
130
g_autoptr(GDesktopAppInfo) info = NULL;
132
info = g_desktop_app_info_new(LIVEPATCH_DESKTOP_FILE);
137
livepatch_is_supported()
139
g_autoptr(GKeyFile) file = NULL;
140
g_autofree gchar *version = NULL;
141
g_autoptr(GError) error = NULL;
143
file = parse_osrelease();
147
version = g_key_file_get_string(file, "os-release", "VERSION", &error);
150
g_warning("Failed to get the version from the file %s: %s",
151
OS_RELEASE_PATH, error->message);
155
return g_strstr_len(version, -1, "LTS") != NULL;
159
livepatch_is_running()
161
g_autoptr(JsonNode) result_node = NULL;
162
JsonNode *running_node = NULL;
163
JsonArray *result_array;
165
result_node = livepatch_get_status_node("$.Status[0].Running", NULL);
166
if (result_node == NULL)
169
result_array = json_node_get_array(result_node);
171
if (json_array_get_length(result_array) == 0)
174
running_node = json_array_get_element(result_array, 0);
175
return json_node_get_boolean(running_node);
179
livepatch_get_state(GError **error)
181
g_autoptr(JsonNode) result_node = NULL;
182
JsonNode *state_node = NULL;
183
JsonArray *result_array;
184
const gchar *expr = "$.Status[0].Livepatch.State";
186
result_node = livepatch_get_status_node(expr, error);
187
if (result_node == NULL)
190
result_array = json_node_get_array(result_node);
192
if (json_array_get_length(result_array) == 0)
195
LIVEPATCH_ERROR, LIVEPATCH_ERROR_NOMATCH,
196
"No matches for: %s", expr);
200
state_node = json_array_get_element(result_array, 0);
201
return g_strdup(json_node_get_string(state_node));
205
livepatch_get_check_state(GError **error)
207
g_autoptr(JsonNode) result_node = NULL;
208
JsonNode *state_node = NULL;
209
JsonArray *result_array;
210
const gchar *expr = "$.Status[0].Livepatch.CheckState";
212
result_node = livepatch_get_status_node(expr, error);
213
if (result_node == NULL)
216
result_array = json_node_get_array(result_node);
218
if (json_array_get_length(result_array) == 0)
221
LIVEPATCH_ERROR, LIVEPATCH_ERROR_NOMATCH,
222
"No matches for: %s", expr);
226
state_node = json_array_get_element(result_array, 0);
227
return g_strdup(json_node_get_string(state_node));
231
livepatch_get_num_fixes(GError **error)
233
g_autoptr(JsonNode) node = NULL;
236
node = livepatch_get_status_node("$.Status[0].Livepatch.Fixes[*]", error);
240
array = json_node_get_array(node);
241
return json_array_get_length(array);