1 /*
2 * libosinfo: An installation tree for a (guest) OS
3 *
4 * Copyright (C) 2009-2020 Red Hat, Inc.
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library. If not, see
18 * <http://www.gnu.org/licenses/>.
19 */
20
21 #include <osinfo/osinfo.h>
22 #include "osinfo_util_private.h"
23 #include <gio/gio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <glib/gi18n-lib.h>
27 #include <libsoup/soup.h>
28
29 typedef struct _CreateFromLocationAsyncData CreateFromLocationAsyncData;
30 struct _CreateFromLocationAsyncData {
31 SoupSession *session;
32 SoupMessage *message;
33 GFile *file;
34
35 gchar *content;
36 gchar *location;
37 gchar *treeinfo;
38
39 GTask *res;
40 };
41
create_from_location_async_data_free(CreateFromLocationAsyncData * data)42 static void create_from_location_async_data_free(CreateFromLocationAsyncData *data)
43 {
44 g_clear_object(&data->session);
45 g_clear_object(&data->message);
46 g_clear_object(&data->file);
47 g_clear_object(&data->res);
48
49 g_slice_free(CreateFromLocationAsyncData, data);
50 }
51
52 typedef struct _CreateFromLocationData CreateFromLocationData;
53 struct _CreateFromLocationData {
54 GMainLoop *main_loop;
55
56 GAsyncResult *res;
57 };
58
create_from_location_data_free(CreateFromLocationData * data)59 static void create_from_location_data_free(CreateFromLocationData *data)
60 {
61 g_object_unref(data->res);
62 g_main_loop_unref(data->main_loop);
63
64 g_slice_free(CreateFromLocationData, data);
65 }
66
67 /**
68 * osinfo_tree_error_quark:
69 *
70 * Gets a #GQuark representing the string "osinfo-tree-error"
71 *
72 * Returns: the #GQuark representing the string.
73 *
74 * Since: 0.1.0
75 */
76 GQuark
osinfo_tree_error_quark(void)77 osinfo_tree_error_quark(void)
78 {
79 static GQuark quark = 0;
80
81 if (!quark)
82 quark = g_quark_from_static_string("osinfo-tree-error");
83
84 return quark;
85 }
86
87 /**
88 * SECTION:osinfo_tree
89 * @short_description: An installation tree for a (guest) OS
90 * @see_also: #OsinfoOs
91 *
92 * #OsinfoTree is an entity representing an installation tree
93 * a (guest) operating system.
94 */
95
96 struct _OsinfoTreePrivate
97 {
98 GWeakRef os;
99 };
100
101 G_DEFINE_TYPE_WITH_PRIVATE(OsinfoTree, osinfo_tree, OSINFO_TYPE_ENTITY);
102
103 enum {
104 PROP_0,
105
106 PROP_ARCHITECTURE,
107 PROP_URL,
108 PROP_TREEINFO_FAMILY,
109 PROP_TREEINFO_VARIANT,
110 PROP_TREEINFO_VERSION,
111 PROP_TREEINFO_ARCH,
112 PROP_KERNEL_PATH,
113 PROP_INITRD_PATH,
114 PROP_BOOT_ISO_PATH,
115 PROP_HAS_TREEINFO,
116 PROP_OS,
117
118 LAST_PROP
119 };
120 static GParamSpec *properties[LAST_PROP];
121
122 static void
osinfo_tree_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)123 osinfo_tree_get_property(GObject *object,
124 guint property_id,
125 GValue *value,
126 GParamSpec *pspec)
127 {
128 OsinfoTree *tree = OSINFO_TREE(object);
129
130 switch (property_id) {
131 case PROP_ARCHITECTURE:
132 g_value_set_string(value,
133 osinfo_tree_get_architecture(tree));
134 break;
135
136 case PROP_URL:
137 g_value_set_string(value,
138 osinfo_tree_get_url(tree));
139 break;
140
141 case PROP_TREEINFO_FAMILY:
142 g_value_set_string(value,
143 osinfo_tree_get_treeinfo_family(tree));
144 break;
145
146 case PROP_TREEINFO_VARIANT:
147 g_value_set_string(value,
148 osinfo_tree_get_treeinfo_variant(tree));
149 break;
150
151 case PROP_TREEINFO_VERSION:
152 g_value_set_string(value,
153 osinfo_tree_get_treeinfo_version(tree));
154 break;
155
156 case PROP_TREEINFO_ARCH:
157 g_value_set_string(value,
158 osinfo_tree_get_treeinfo_arch(tree));
159 break;
160
161 case PROP_KERNEL_PATH:
162 g_value_set_string(value,
163 osinfo_tree_get_kernel_path(tree));
164 break;
165
166 case PROP_INITRD_PATH:
167 g_value_set_string(value,
168 osinfo_tree_get_initrd_path(tree));
169 break;
170
171 case PROP_BOOT_ISO_PATH:
172 g_value_set_string(value,
173 osinfo_tree_get_boot_iso_path(tree));
174 break;
175
176 case PROP_HAS_TREEINFO:
177 g_value_set_boolean(value,
178 osinfo_tree_has_treeinfo(tree));
179 break;
180
181 case PROP_OS:
182 g_value_take_object(value, osinfo_tree_get_os(tree));
183 break;
184
185 default:
186 /* We don't have any other property... */
187 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
188 break;
189 }
190 }
191
192
193 static void
osinfo_tree_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)194 osinfo_tree_set_property(GObject *object,
195 guint property_id,
196 const GValue *value,
197 GParamSpec *pspec)
198 {
199 OsinfoTree *tree = OSINFO_TREE(object);
200
201 switch (property_id) {
202 case PROP_ARCHITECTURE:
203 osinfo_entity_set_param(OSINFO_ENTITY(tree),
204 OSINFO_TREE_PROP_ARCHITECTURE,
205 g_value_get_string(value));
206 break;
207
208 case PROP_URL:
209 osinfo_entity_set_param(OSINFO_ENTITY(tree),
210 OSINFO_TREE_PROP_URL,
211 g_value_get_string(value));
212 break;
213
214 case PROP_TREEINFO_FAMILY:
215 osinfo_entity_set_param(OSINFO_ENTITY(tree),
216 OSINFO_TREE_PROP_TREEINFO_FAMILY,
217 g_value_get_string(value));
218 break;
219
220 case PROP_TREEINFO_VARIANT:
221 osinfo_entity_set_param(OSINFO_ENTITY(tree),
222 OSINFO_TREE_PROP_TREEINFO_VARIANT,
223 g_value_get_string(value));
224 break;
225
226 case PROP_TREEINFO_VERSION:
227 osinfo_entity_set_param(OSINFO_ENTITY(tree),
228 OSINFO_TREE_PROP_TREEINFO_VERSION,
229 g_value_get_string(value));
230 break;
231
232 case PROP_TREEINFO_ARCH:
233 osinfo_entity_set_param(OSINFO_ENTITY(tree),
234 OSINFO_TREE_PROP_TREEINFO_ARCH,
235 g_value_get_string(value));
236 break;
237
238 case PROP_KERNEL_PATH:
239 osinfo_entity_set_param(OSINFO_ENTITY(tree),
240 OSINFO_TREE_PROP_KERNEL,
241 g_value_get_string(value));
242 break;
243
244 case PROP_INITRD_PATH:
245 osinfo_entity_set_param(OSINFO_ENTITY(tree),
246 OSINFO_TREE_PROP_INITRD,
247 g_value_get_string(value));
248 break;
249
250 case PROP_BOOT_ISO_PATH:
251 osinfo_entity_set_param(OSINFO_ENTITY(tree),
252 OSINFO_TREE_PROP_BOOT_ISO,
253 g_value_get_string(value));
254 break;
255
256 case PROP_HAS_TREEINFO:
257 osinfo_entity_set_param_boolean(OSINFO_ENTITY(tree),
258 OSINFO_TREE_PROP_HAS_TREEINFO,
259 g_value_get_boolean(value));
260 break;
261
262 case PROP_OS:
263 osinfo_tree_set_os(tree, g_value_get_object(value));
264 break;
265
266 default:
267 /* We don't have any other property... */
268 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
269 break;
270 }
271 }
272
273 static void
osinfo_tree_finalize(GObject * object)274 osinfo_tree_finalize(GObject *object)
275 {
276 /* Chain up to the parent class */
277 G_OBJECT_CLASS(osinfo_tree_parent_class)->finalize(object);
278 }
279
osinfo_tree_dispose(GObject * obj)280 static void osinfo_tree_dispose(GObject *obj)
281 {
282 OsinfoTree *tree = OSINFO_TREE(obj);
283
284 g_weak_ref_clear(&tree->priv->os);
285
286 G_OBJECT_CLASS(osinfo_tree_parent_class)->dispose(obj);
287 }
288
289 /* Init functions */
290 static void
osinfo_tree_class_init(OsinfoTreeClass * klass)291 osinfo_tree_class_init(OsinfoTreeClass *klass)
292 {
293 GObjectClass *g_klass = G_OBJECT_CLASS(klass);
294
295 g_klass->dispose = osinfo_tree_dispose;
296 g_klass->finalize = osinfo_tree_finalize;
297 g_klass->get_property = osinfo_tree_get_property;
298 g_klass->set_property = osinfo_tree_set_property;
299
300 /**
301 * OsinfoTree:architecture:
302 *
303 * The target hardware architecture of this tree.
304 */
305 properties[PROP_ARCHITECTURE] = g_param_spec_string("architecture",
306 "ARCHITECTURE",
307 _("CPU Architecture"),
308 NULL /* default value */,
309 G_PARAM_READWRITE |
310 G_PARAM_STATIC_STRINGS);
311
312 /**
313 * OsinfoTree:url:
314 *
315 * The URL to this tree.
316 */
317 properties[PROP_URL] = g_param_spec_string("url",
318 "URL",
319 _("The URL to this tree"),
320 NULL /* default value */,
321 G_PARAM_READWRITE |
322 G_PARAM_STATIC_STRINGS);
323
324 /**
325 * OsinfoTree:kernel-path:
326 *
327 * The path to the kernel image in the install tree.
328 */
329 properties[PROP_KERNEL_PATH] = g_param_spec_string("kernel-path",
330 "KernelPath",
331 _("The path to the kernel image"),
332 NULL /* default value */,
333 G_PARAM_READWRITE |
334 G_PARAM_STATIC_STRINGS);
335
336 /**
337 * OsinfoTree:initrd-path:
338 *
339 * The path to the initrd image in the install tree.
340 */
341 properties[PROP_INITRD_PATH] = g_param_spec_string("initrd-path",
342 "InitrdPath",
343 _("The path to the initrd image"),
344 NULL /* default value */,
345 G_PARAM_READWRITE |
346 G_PARAM_STATIC_STRINGS);
347
348 /**
349 * OsinfoTree:boot-iso-path:
350 *
351 * The path to the boot ISO in the install tree
352 */
353 properties[PROP_BOOT_ISO_PATH] = g_param_spec_string("boot-iso-path",
354 "BootISOPath",
355 _("The path to the bootable ISO image"),
356 NULL /* default value */,
357 G_PARAM_READWRITE |
358 G_PARAM_STATIC_STRINGS);
359
360 /**
361 * OsinfoTree:has-treeinfo
362 *
363 * Whether the tree has treeinfo or not
364 */
365 properties[PROP_HAS_TREEINFO] = g_param_spec_boolean("has-treeinfo",
366 "HasTreeinfo",
367 _("Whether the tree has treeinfo"),
368 FALSE /* default value */,
369 G_PARAM_READWRITE |
370 G_PARAM_STATIC_STRINGS);
371
372 /**
373 * OsinfoTree:treeinfo-family
374 *
375 * The treeinfo family
376 */
377 properties[PROP_TREEINFO_FAMILY] = g_param_spec_string("treeinfo-family",
378 "TreeInfoFamily",
379 _("The treeinfo family"),
380 NULL /* default value */,
381 G_PARAM_READWRITE |
382 G_PARAM_STATIC_STRINGS);
383
384 /**
385 * OsinfoTree:treeinfo-variant
386 *
387 * The treeinfo variant
388 */
389 properties[PROP_TREEINFO_VARIANT] = g_param_spec_string("treeinfo-variant",
390 "TreeInfoVariant",
391 _("The treeinfo variant"),
392 NULL /* default value */,
393 G_PARAM_READWRITE |
394 G_PARAM_STATIC_STRINGS);
395
396 /**
397 * OsinfoTree:treeinfo-version
398 *
399 * The treeinfo version
400 */
401 properties[PROP_TREEINFO_VERSION] = g_param_spec_string("treeinfo-version",
402 "TreeInfoVersion",
403 _("The treeinfo version"),
404 NULL /* default value */,
405 G_PARAM_READWRITE |
406 G_PARAM_STATIC_STRINGS);
407
408 /**
409 * OsinfoTree:treeinfo-arch
410 *
411 * The treeinfo arch
412 */
413 properties[PROP_TREEINFO_ARCH] = g_param_spec_string("treeinfo-arch",
414 "TreeInfoArch",
415 _("The treeinfo architecture"),
416 NULL /* default value */,
417 G_PARAM_READWRITE |
418 G_PARAM_STATIC_STRINGS);
419
420 /**
421 * OsinfoTree:os:
422 *
423 * Os information for the current tree. For tree stored in an
424 * #OsinfoDb, it will be filled when the database is loaded, otherwise
425 * the property will be filled after a successful call to
426 * osinfo_db_identify_tree().
427 */
428 properties[PROP_OS] = g_param_spec_object("os",
429 "Os",
430 _("Information about the operating system on this tree"),
431 OSINFO_TYPE_OS,
432 G_PARAM_READWRITE |
433 G_PARAM_STATIC_STRINGS);
434
435 g_object_class_install_properties(g_klass, LAST_PROP, properties);
436 }
437
438 static void
osinfo_tree_init(OsinfoTree * tree)439 osinfo_tree_init(OsinfoTree *tree)
440 {
441 tree->priv = osinfo_tree_get_instance_private(tree);
442
443 g_weak_ref_init(&tree->priv->os, NULL);
444 }
445
446 /**
447 * osinfo_tree_new:
448 * @id: the id of the tree to be created
449 * @architecture: the architecture of the tree to be created
450 *
451 * Create a new tree entity
452 *
453 * Returns: (transfer full): A tree entity
454 *
455 * Since: 0.1.0
456 */
osinfo_tree_new(const gchar * id,const gchar * architecture)457 OsinfoTree *osinfo_tree_new(const gchar *id,
458 const gchar *architecture)
459 {
460 OsinfoTree *tree;
461
462 tree = g_object_new(OSINFO_TYPE_TREE,
463 "id", id,
464 NULL);
465
466 osinfo_entity_set_param(OSINFO_ENTITY(tree),
467 OSINFO_TREE_PROP_ARCHITECTURE,
468 architecture);
469
470 return tree;
471 }
472
on_tree_create_from_location_ready(GObject * source_object,GAsyncResult * res,gpointer user_data)473 static void on_tree_create_from_location_ready(GObject *source_object,
474 GAsyncResult *res,
475 gpointer user_data)
476 {
477 CreateFromLocationData *data = (CreateFromLocationData *)user_data;
478
479 data->res = g_object_ref(res);
480
481 g_main_loop_quit(data->main_loop);
482 }
483
484 /**
485 * osinfo_tree_create_from_location:
486 * @location: the location of an installation tree
487 * @cancellable: (allow-none): a #GCancellable, or %NULL
488 * @error: The location where to store any error, or %NULL
489 *
490 * Creates a new #OsinfoTree for installation tree at @location. The @location
491 * could be a http:// or a https:// URI, or a local file.
492 *
493 * NOTE: Currently this only works for trees with a .treeinfo file
494 *
495 * Returns: (transfer full): a new #OsinfoTree , or NULL on error
496 *
497 * Since: 0.1.0
498 */
osinfo_tree_create_from_location(const gchar * location,GCancellable * cancellable,GError ** error)499 OsinfoTree *osinfo_tree_create_from_location(const gchar *location,
500 GCancellable *cancellable,
501 GError **error)
502 {
503 CreateFromLocationData *data;
504 OsinfoTree *ret;
505
506 data = g_slice_new0(CreateFromLocationData);
507 data->main_loop = g_main_loop_new(g_main_context_get_thread_default(),
508 FALSE);
509
510 osinfo_tree_create_from_location_async(location,
511 G_PRIORITY_DEFAULT,
512 cancellable,
513 on_tree_create_from_location_ready,
514 data);
515
516 /* Loop till we get a reply (or time out) */
517 g_main_loop_run(data->main_loop);
518
519 ret = osinfo_tree_create_from_location_finish(data->res, error);
520 create_from_location_data_free(data);
521
522 return ret;
523 }
524
is_str_empty(const gchar * str)525 static gboolean is_str_empty(const gchar *str) {
526 guint8 i;
527 gboolean ret = TRUE;
528
529 if ((str == NULL) || (*str == 0))
530 return TRUE;
531
532 for (i = 0; i < strlen(str); i++)
533 if (!g_ascii_isspace(str[i])) {
534 ret = FALSE;
535
536 break;
537 }
538
539 return ret;
540 }
541
is_unknown_group_or_key_error(const GError * error)542 static gboolean is_unknown_group_or_key_error(const GError *error)
543 {
544 return (g_error_matches(error, G_KEY_FILE_ERROR,
545 G_KEY_FILE_ERROR_KEY_NOT_FOUND) ||
546 g_error_matches(error, G_KEY_FILE_ERROR,
547 G_KEY_FILE_ERROR_GROUP_NOT_FOUND));
548 }
549
load_keyinfo(const gchar * location,const gchar * content,gsize length,GError ** error)550 static OsinfoTree *load_keyinfo(const gchar *location,
551 const gchar *content,
552 gsize length,
553 GError **error)
554 {
555 GKeyFile *file = g_key_file_new();
556 OsinfoTree *tree = NULL;
557 gchar *family = NULL;
558 gchar *variant = NULL;
559 gchar *version = NULL;
560 gchar *arch = NULL;
561 gchar *kernel = NULL;
562 gchar *initrd = NULL;
563 gchar *bootiso = NULL;
564 gchar *group = NULL;
565
566 if (!g_key_file_load_from_data(file, content, length,
567 G_KEY_FILE_NONE, error))
568 goto cleanup;
569
570 if (!(family = g_key_file_get_string(file, "general", "family", error))) {
571 if (!is_unknown_group_or_key_error(*error))
572 goto cleanup;
573 g_clear_error(error);
574 }
575
576 if (!(variant = g_key_file_get_string(file, "general", "variant", error))) {
577 if (!is_unknown_group_or_key_error(*error))
578 goto cleanup;
579 g_clear_error(error);
580 }
581
582 if (!(version = g_key_file_get_string(file, "general", "version", error))) {
583 if (!is_unknown_group_or_key_error(*error))
584 goto cleanup;
585 g_clear_error(error);
586 }
587
588 if (!(arch = g_key_file_get_string(file, "general", "arch", error))) {
589 if (!is_unknown_group_or_key_error(*error))
590 goto cleanup;
591 g_clear_error(error);
592 }
593
594
595 if (arch) {
596 group = g_strdup_printf("images-%s", arch);
597
598 if (!(kernel = g_key_file_get_string(file, group, "kernel", error))) {
599 if (!is_unknown_group_or_key_error(*error))
600 goto cleanup;
601 g_clear_error(error);
602 }
603
604 if (!(initrd = g_key_file_get_string(file, group, "initrd", error))) {
605 if (!is_unknown_group_or_key_error(*error))
606 goto cleanup;
607 g_clear_error(error);
608 }
609
610 if (!(bootiso = g_key_file_get_string(file, group, "boot.iso", error))) {
611 if (!is_unknown_group_or_key_error(*error))
612 goto cleanup;
613 g_clear_error(error);
614 }
615 }
616
617 tree = osinfo_tree_new(location, arch ? arch : "i386");
618
619 osinfo_entity_set_param(OSINFO_ENTITY(tree),
620 OSINFO_TREE_PROP_URL,
621 location);
622
623 if (!is_str_empty(family))
624 osinfo_entity_set_param(OSINFO_ENTITY(tree),
625 OSINFO_TREE_PROP_TREEINFO_FAMILY,
626 family);
627 if (!is_str_empty(variant))
628 osinfo_entity_set_param(OSINFO_ENTITY(tree),
629 OSINFO_TREE_PROP_TREEINFO_VARIANT,
630 variant);
631 if (!is_str_empty(version))
632 osinfo_entity_set_param(OSINFO_ENTITY(tree),
633 OSINFO_TREE_PROP_TREEINFO_VERSION,
634 version);
635 if (!is_str_empty(arch))
636 osinfo_entity_set_param(OSINFO_ENTITY(tree),
637 OSINFO_TREE_PROP_TREEINFO_ARCH,
638 arch);
639 if (!is_str_empty(kernel))
640 osinfo_entity_set_param(OSINFO_ENTITY(tree),
641 OSINFO_TREE_PROP_KERNEL,
642 kernel);
643 if (!is_str_empty(initrd))
644 osinfo_entity_set_param(OSINFO_ENTITY(tree),
645 OSINFO_TREE_PROP_INITRD,
646 initrd);
647 if (!is_str_empty(bootiso))
648 osinfo_entity_set_param(OSINFO_ENTITY(tree),
649 OSINFO_TREE_PROP_BOOT_ISO,
650 bootiso);
651
652 cleanup:
653 g_free(family);
654 g_free(variant);
655 g_free(version);
656 g_free(arch);
657 g_free(kernel);
658 g_free(initrd);
659 g_free(bootiso);
660 g_key_file_free(file);
661 return tree;
662 }
663
664 static void
665 osinfo_tree_create_from_location_async_helper(CreateFromLocationAsyncData *data,
666 const gchar *treeinfo);
667
on_content_read(GObject * source,GAsyncResult * res,gpointer user_data)668 static void on_content_read(GObject *source,
669 GAsyncResult *res,
670 gpointer user_data)
671 {
672 CreateFromLocationAsyncData *data;
673 gsize length = 0;
674 GError *error = NULL;
675 OsinfoTree *ret;
676
677 data = (CreateFromLocationAsyncData *)user_data;
678
679 if (!g_input_stream_read_all_finish(G_INPUT_STREAM(source),
680 res,
681 &length,
682 &error)) {
683 g_prefix_error(&error, _("Failed to load .treeinfo|treeinfo content: "));
684 g_task_return_error(data->res, error);
685 goto cleanup;
686 }
687
688 if (!(ret = load_keyinfo(data->location,
689 data->content,
690 length,
691 &error))) {
692 g_prefix_error(&error, _("Failed to process keyinfo file: "));
693 g_task_return_error(data->res, error);
694 goto cleanup;
695 }
696
697 g_task_return_pointer(data->res, ret, g_object_unref);
698
699 cleanup:
700 create_from_location_async_data_free(data);
701 }
702
on_soup_location_read(GObject * source,GAsyncResult * res,gpointer user_data)703 static void on_soup_location_read(GObject *source,
704 GAsyncResult *res,
705 gpointer user_data)
706 {
707 CreateFromLocationAsyncData *data;
708 GError *error = NULL;
709 GInputStream *stream;
710 goffset content_size;
711
712 data = (CreateFromLocationAsyncData *)user_data;
713
714 stream = soup_session_send_finish(SOUP_SESSION(source),
715 res,
716 &error);
717 if (stream == NULL ||
718 !SOUP_STATUS_IS_SUCCESSFUL(data->message->status_code)) {
719 /* It means no ".treeinfo" file has been found. Try again, this time
720 * looking for a "treeinfo" file. */
721 if (g_str_equal(data->treeinfo, ".treeinfo")) {
722 osinfo_tree_create_from_location_async_helper(data, "treeinfo");
723 return;
724 }
725
726 if (error == NULL) {
727 g_set_error_literal(&error,
728 OSINFO_TREE_ERROR,
729 OSINFO_TREE_ERROR_NO_TREEINFO,
730 soup_status_get_phrase(data->message->status_code));
731 }
732 g_prefix_error(&error, _("Failed to load .treeinfo|treeinfo file: "));
733 g_task_return_error(data->res, error);
734 create_from_location_async_data_free(data);
735 return;
736 }
737
738 content_size = soup_message_headers_get_content_length(data->message->response_headers);
739 data->content = g_malloc0(content_size);
740
741 g_input_stream_read_all_async(stream,
742 data->content,
743 content_size,
744 g_task_get_priority(data->res),
745 g_task_get_cancellable(data->res),
746 on_content_read,
747 data);
748 }
749
on_local_location_read(GObject * source,GAsyncResult * res,gpointer user_data)750 static void on_local_location_read(GObject *source,
751 GAsyncResult *res,
752 gpointer user_data)
753 {
754 CreateFromLocationAsyncData *data;
755 GError *error = NULL;
756 gchar *content = NULL;
757 gsize length = 0;
758 OsinfoTree *ret = NULL;
759
760 data = (CreateFromLocationAsyncData *)user_data;
761
762 if (!g_file_load_contents_finish(G_FILE(source),
763 res,
764 &content,
765 &length,
766 NULL,
767 &error)) {
768 if (g_str_equal(data->treeinfo, ".treeinfo")) {
769 osinfo_tree_create_from_location_async_helper(data, "treeinfo");
770 return;
771 }
772
773 g_prefix_error(&error, _("Failed to load .treeinfo|treeinfo file: "));
774 g_task_return_error(data->res, error);
775 goto cleanup;
776 }
777
778 if (!(ret = load_keyinfo(data->location,
779 content,
780 length,
781 &error))) {
782 g_prefix_error(&error, _("Failed to process keyinfo file: "));
783 g_task_return_error(data->res, error);
784 goto cleanup;
785 }
786
787 g_task_return_pointer(data->res, ret, g_object_unref);
788
789 cleanup:
790 create_from_location_async_data_free(data);
791 g_free(content);
792 }
793
794 static void
osinfo_tree_create_from_location_async_helper(CreateFromLocationAsyncData * data,const gchar * treeinfo)795 osinfo_tree_create_from_location_async_helper(CreateFromLocationAsyncData *data,
796 const gchar *treeinfo)
797 {
798 gchar *location;
799 gboolean requires_soup;
800
801 g_return_if_fail(treeinfo != NULL);
802
803 requires_soup = osinfo_util_requires_soup(data->location);
804 if (!requires_soup &&
805 !g_str_has_prefix(data->location, "file://")) {
806 GError *error = NULL;
807
808 g_set_error_literal(&error,
809 OSINFO_TREE_ERROR,
810 OSINFO_TREE_ERROR_NOT_SUPPORTED_PROTOCOL,
811 _("URL protocol is not supported"));
812
813 g_task_return_error(data->res, error);
814 create_from_location_async_data_free(data);
815 return;
816 }
817
818 location = g_strdup_printf("%s/%s", data->location, treeinfo);
819
820 g_free(data->treeinfo);
821 data->treeinfo = g_strdup(treeinfo);
822
823 if (requires_soup) {
824 if (data->session == NULL)
825 data->session = soup_session_new_with_options(
826 SOUP_SESSION_USER_AGENT, "Wget/1.0",
827 NULL);
828
829 g_clear_object(&data->message);
830 data->message = soup_message_new("GET", location);
831
832 soup_session_send_async(data->session,
833 data->message,
834 g_task_get_cancellable(data->res),
835 on_soup_location_read,
836 data);
837 } else {
838 g_clear_object(&data->file);
839 data->file = g_file_new_for_uri(location);
840
841 g_file_load_contents_async(data->file,
842 g_task_get_cancellable(data->res),
843 on_local_location_read,
844 data);
845 }
846 g_free(location);
847 }
848
849 /**
850 * osinfo_tree_create_from_location_async:
851 * @location: the location of an installation tree
852 * @priority: the I/O priority of the request
853 * @cancellable: (allow-none): a #GCancellable, or %NULL
854 * @callback: Function to call when result of this call is ready
855 * @user_data: The user data to pass to @callback, or %NULL
856 *
857 * Asynchronous variant of #osinfo_tree_create_from_location.
858 *
859 * Since: 0.1.0
860 */
osinfo_tree_create_from_location_async(const gchar * location,gint priority,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)861 void osinfo_tree_create_from_location_async(const gchar *location,
862 gint priority,
863 GCancellable *cancellable,
864 GAsyncReadyCallback callback,
865 gpointer user_data)
866 {
867 CreateFromLocationAsyncData *data;
868
869 data = g_slice_new0(CreateFromLocationAsyncData);
870 data->res = g_task_new(NULL,
871 cancellable,
872 callback,
873 user_data);
874 g_task_set_priority(data->res, priority);
875
876 data->location = g_strdup(location);
877
878 osinfo_tree_create_from_location_async_helper(data, ".treeinfo");
879 }
880
881
882 /**
883 * osinfo_tree_create_from_location_finish:
884 * @res: a #GAsyncResult
885 * @error: The location where to store any error, or %NULL
886 *
887 * Finishes an asynchronous tree object creation process started with
888 * #osinfo_tree_create_from_location_async.
889 *
890 * Returns: (transfer full): a new #OsinfoTree , or NULL on error
891 *
892 * Since: 0.1.0
893 */
osinfo_tree_create_from_location_finish(GAsyncResult * res,GError ** error)894 OsinfoTree *osinfo_tree_create_from_location_finish(GAsyncResult *res,
895 GError **error)
896 {
897 GTask *task = G_TASK(res);
898
899 g_return_val_if_fail(error == NULL || *error == NULL, NULL);
900
901 return g_task_propagate_pointer(task, error);
902 }
903
904 /**
905 * osinfo_tree_get_architecture:
906 * @tree: an #OsinfoTree instance
907 *
908 * Retrieves the target hardware architecture of the OS @tree provides.
909 *
910 * Returns: (transfer none): the hardware architecture, or NULL
911 *
912 * Since: 0.1.0
913 */
osinfo_tree_get_architecture(OsinfoTree * tree)914 const gchar *osinfo_tree_get_architecture(OsinfoTree *tree)
915 {
916 return osinfo_entity_get_param_value(OSINFO_ENTITY(tree),
917 OSINFO_TREE_PROP_ARCHITECTURE);
918 }
919
920 /**
921 * osinfo_tree_get_url:
922 * @tree: an #OsinfoTree instance
923 *
924 * The URL to the @tree
925 *
926 * Returns: (transfer none): the URL, or NULL
927 *
928 * Since: 0.1.0
929 */
osinfo_tree_get_url(OsinfoTree * tree)930 const gchar *osinfo_tree_get_url(OsinfoTree *tree)
931 {
932 return osinfo_entity_get_param_value(OSINFO_ENTITY(tree),
933 OSINFO_TREE_PROP_URL);
934 }
935
936 /**
937 * osinfo_tree_get_treeinfo_family:
938 * @tree: an #OsinfoTree instance
939 *
940 * If @tree has treeinfo, this function retrieves the expected family.
941 *
942 * Note: In practice, this will usually not be the exact copy of the family
943 * but rather a regular expression that matches it.
944 *
945 * Returns: (transfer none): the treeinfo family, or NULL
946 *
947 * Since: 0.1.0
948 */
osinfo_tree_get_treeinfo_family(OsinfoTree * tree)949 const gchar *osinfo_tree_get_treeinfo_family(OsinfoTree *tree)
950 {
951 return osinfo_entity_get_param_value(OSINFO_ENTITY(tree),
952 OSINFO_TREE_PROP_TREEINFO_FAMILY);
953 }
954
955 /**
956 * osinfo_tree_get_treeinfo_arch:
957 * @tree: an #OsinfoTree instance
958 *
959 * If @tree has treeinfo, this function retrieves the expected architecture.
960 *
961 * Note: In practice, this will usually not be the exact copy of the
962 * architecture but rather a regular expression that matches it.
963 *
964 * Returns: (transfer none): the treeinfo architecture, or NULL
965 *
966 * Since: 0.1.0
967 */
osinfo_tree_get_treeinfo_arch(OsinfoTree * tree)968 const gchar *osinfo_tree_get_treeinfo_arch(OsinfoTree *tree)
969 {
970 return osinfo_entity_get_param_value(OSINFO_ENTITY(tree),
971 OSINFO_TREE_PROP_TREEINFO_ARCH);
972 }
973
974 /**
975 * osinfo_tree_get_treeinfo_variant:
976 * @tree: an #OsinfoTree instance
977 *
978 * If @tree has treeinfo, this function retrieves the expected variant.
979 *
980 * Note: In practice, this will usually not be the exact copy of the variant
981 * but rather a regular expression that matches it.
982 *
983 * Returns: (transfer none): the treeinfo variant, or NULL
984 *
985 * Since: 0.1.0
986 */
osinfo_tree_get_treeinfo_variant(OsinfoTree * tree)987 const gchar *osinfo_tree_get_treeinfo_variant(OsinfoTree *tree)
988 {
989 return osinfo_entity_get_param_value(OSINFO_ENTITY(tree),
990 OSINFO_TREE_PROP_TREEINFO_VARIANT);
991 }
992
993 /**
994 * osinfo_tree_get_treeinfo_version:
995 * @tree: an #OsinfoTree instance
996 *
997 * If @tree has treeinfo, this function retrieves the expected version.
998 *
999 * Note: In practice, this will usually not be the exact copy of version but
1000 * rather a regular expression that matches it.
1001 *
1002 * Returns: (transfer none): the treeinfo version, or NULL
1003 *
1004 * Since: 0.1.0
1005 */
osinfo_tree_get_treeinfo_version(OsinfoTree * tree)1006 const gchar *osinfo_tree_get_treeinfo_version(OsinfoTree *tree)
1007 {
1008 return osinfo_entity_get_param_value(OSINFO_ENTITY(tree),
1009 OSINFO_TREE_PROP_TREEINFO_VERSION);
1010 }
1011
1012 /**
1013 * osinfo_tree_get_boot_iso_path:
1014 * @tree: an #OsinfoTree instance
1015 *
1016 * Retrieves the path to the boot_iso image in the install tree.
1017 *
1018 * Returns: (transfer none): the path to boot_iso image, or NULL
1019 *
1020 * Since: 0.1.0
1021 */
osinfo_tree_get_boot_iso_path(OsinfoTree * tree)1022 const gchar *osinfo_tree_get_boot_iso_path(OsinfoTree *tree)
1023 {
1024 return osinfo_entity_get_param_value(OSINFO_ENTITY(tree),
1025 OSINFO_TREE_PROP_BOOT_ISO);
1026 }
1027
1028 /**
1029 * osinfo_tree_get_kernel_path:
1030 * @tree: an #OsinfoTree instance
1031 *
1032 * Retrieves the path to the kernel image in the install tree.
1033 *
1034 * Note: This only applies to installer trees of 'linux' OS family.
1035 *
1036 * Returns: (transfer none): the path to kernel image, or NULL
1037 *
1038 * Since: 0.1.0
1039 */
osinfo_tree_get_kernel_path(OsinfoTree * tree)1040 const gchar *osinfo_tree_get_kernel_path(OsinfoTree *tree)
1041 {
1042 return osinfo_entity_get_param_value(OSINFO_ENTITY(tree),
1043 OSINFO_TREE_PROP_KERNEL);
1044 }
1045
1046 /**
1047 * osinfo_tree_get_initrd_path:
1048 * @tree: an #OsinfoTree instance
1049 *
1050 * Retrieves the path to the initrd image in the install tree.
1051 *
1052 * Note: This only applies to installer trees of 'linux' OS family.
1053 *
1054 * Returns: (transfer none): the path to initrd image, or NULL
1055 *
1056 * Since: 0.1.0
1057 */
osinfo_tree_get_initrd_path(OsinfoTree * tree)1058 const gchar *osinfo_tree_get_initrd_path(OsinfoTree *tree)
1059 {
1060 return osinfo_entity_get_param_value(OSINFO_ENTITY(tree),
1061 OSINFO_TREE_PROP_INITRD);
1062 }
1063
1064 /**
1065 * osinfo_tree_has_treeinfo:
1066 * @tree: an #OsinfoTree instance
1067 *
1068 * Return whether a tree has treeinfo or not.
1069 *
1070 * Returns: TRUE if the tree has treeinfo. FALSE otherwise.
1071 *
1072 * Since: 1.3.0
1073 */
osinfo_tree_has_treeinfo(OsinfoTree * tree)1074 gboolean osinfo_tree_has_treeinfo(OsinfoTree *tree)
1075 {
1076 return osinfo_entity_get_param_value_boolean(OSINFO_ENTITY(tree),
1077 OSINFO_TREE_PROP_HAS_TREEINFO);
1078 }
1079
1080 /**
1081 * osinfo_tree_get_os:
1082 * @tree: an #OsinfoTree instance
1083 *
1084 * Returns: (transfer full): the operating system, or NULL
1085 *
1086 * Since: 1.5.0
1087 */
osinfo_tree_get_os(OsinfoTree * tree)1088 OsinfoOs *osinfo_tree_get_os(OsinfoTree *tree)
1089 {
1090 g_return_val_if_fail(OSINFO_IS_TREE(tree), NULL);
1091
1092 return g_weak_ref_get(&tree->priv->os);
1093 }
1094
1095
1096 /**
1097 * osinfo_tree_set_os
1098 * @tree: an #OsinfoTree instance
1099 * @os: an #OsinfoOs instance
1100 *
1101 * Sets the #OsinfoOs associated to the #OsinfoTree instance.
1102 *
1103 * Since: 1.5.0
1104 */
osinfo_tree_set_os(OsinfoTree * tree,OsinfoOs * os)1105 void osinfo_tree_set_os(OsinfoTree *tree, OsinfoOs *os)
1106 {
1107 g_return_if_fail(OSINFO_IS_TREE(tree));
1108
1109 g_object_ref(os);
1110 g_weak_ref_set(&tree->priv->os, os);
1111 g_object_unref(os);
1112 }
1113
1114 /**
1115 * osinfo_tree_get_os_variants:
1116 * @tree: an #OsinfoTree instance
1117 *
1118 * Gets the variants of the associated operating system.
1119 *
1120 * Returns: (transfer full): the operating system variant, or NULL
1121 *
1122 * Since: 1.5.0
1123 */
osinfo_tree_get_os_variants(OsinfoTree * tree)1124 OsinfoOsVariantList *osinfo_tree_get_os_variants(OsinfoTree *tree)
1125 {
1126 OsinfoOs *os;
1127 OsinfoOsVariantList *os_variants;
1128 OsinfoOsVariantList *tree_variants;
1129 GList *ids, *node;
1130 OsinfoFilter *filter;
1131
1132 g_return_val_if_fail(OSINFO_IS_TREE(tree), NULL);
1133
1134 os = osinfo_tree_get_os(tree);
1135 if (os == NULL)
1136 return NULL;
1137
1138 os_variants = osinfo_os_get_variant_list(os);
1139 g_object_unref(os);
1140
1141 ids = osinfo_entity_get_param_value_list(OSINFO_ENTITY(tree),
1142 OSINFO_TREE_PROP_VARIANT);
1143 filter = osinfo_filter_new();
1144 tree_variants = osinfo_os_variantlist_new();
1145 for (node = ids; node != NULL; node = node->next) {
1146 osinfo_filter_clear_constraints(filter);
1147 osinfo_filter_add_constraint(filter,
1148 OSINFO_ENTITY_PROP_ID,
1149 (const char *) node->data);
1150 osinfo_list_add_filtered(OSINFO_LIST(tree_variants),
1151 OSINFO_LIST(os_variants),
1152 filter);
1153 }
1154 g_object_unref(os_variants);
1155
1156 return tree_variants;
1157 }
1158
1159 /**
1160 * osinfo_tree_create_from_treeinfo:
1161 * @treeinfo: a string representing the .treeinfo content
1162 * @location: the location of the original @treeinfo
1163 * @error: The location where to store any error, or %NULL
1164 *
1165 * Creates a new #OsinfoTree for installation tree represented by @treeinfo.
1166 *
1167 * Returns: (transfer full): a new #OsinfoTree, or NULL on error
1168 *
1169 * Since: 1.7.0
1170 */
osinfo_tree_create_from_treeinfo(const gchar * treeinfo,const gchar * location,GError ** error)1171 OsinfoTree *osinfo_tree_create_from_treeinfo(const gchar *treeinfo,
1172 const gchar *location,
1173 GError **error)
1174 {
1175 g_return_val_if_fail(treeinfo != NULL, NULL);
1176 g_return_val_if_fail(location != NULL, NULL);
1177
1178 return load_keyinfo(location, treeinfo, strlen(treeinfo), error);
1179 }
1180