1 /*
2 * libosinfo: An installation media 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_media_private.h"
23 #include "osinfo_util_private.h"
24 #include <gio/gio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <glib/gi18n-lib.h>
28 #include <libsoup/soup.h>
29
30 #define MAX_VOLUME 32
31 #define MAX_SYSTEM 32
32 #define MAX_PUBLISHER 128
33 #define MAX_APPLICATION 128
34
35 #define PVD_OFFSET 0x00008000
36 #define BOOTABLE_TAG "EL TORITO SPECIFICATION"
37 #define PPC_BOOTINFO "/ppc/bootinfo.txt"
38
39 enum {
40 DIRECTORY_RECORD_FLAG_EXISTENCE = 1 << 0,
41 DIRECTORY_RECORD_FLAG_DIRECTORY = 1 << 1,
42 DIRECTORY_RECORD_FLAG_ASSOCIATED_FILE = 1 << 2,
43 DIRECTORY_RECORD_FLAG_RECORD = 1 << 3,
44 DIRECTORY_RECORD_FLAG_PROTECTION = 1 << 4,
45 DIRECTORY_RECORD_FLAG_RESERVED5 = 1 << 5,
46 DIRECTORY_RECORD_FLAG_RESERVED6 = 1 << 6,
47 DIRECTORY_RECORD_FLAG_MULTIEXTENT = 1 << 7
48 };
49
50 typedef struct _DirectoryRecord DirectoryRecord;
51
52 struct __attribute__((packed)) _DirectoryRecord {
53 guint8 length;
54 guint8 ignored;
55 guint32 extent_location[2];
56 guint32 extent_size[2];
57 guint8 ignored2[7];
58 guint8 flags;
59 guint8 ignored3[6];
60 guint8 filename_length;
61 gchar filename[1];
62 };
63
64 G_STATIC_ASSERT(sizeof(struct _DirectoryRecord) == 34);
65
66 typedef struct _PrimaryVolumeDescriptor PrimaryVolumeDescriptor;
67
68 struct _PrimaryVolumeDescriptor {
69 guint8 ignored[8];
70 gchar system[MAX_SYSTEM]; /* System ID */
71 gchar volume[MAX_VOLUME]; /* Volume ID */
72 guint8 ignored2[8];
73 guint32 volume_space_size[2];
74 guint8 ignored3[40];
75 guint16 logical_blk_size[2];
76 guint8 ignored4[24];
77 guint8 root_directory_entry[33];
78 guint8 ignored5[129];
79 gchar publisher[MAX_PUBLISHER]; /* Publisher ID */
80 guint8 ignored6[128];
81 gchar application[MAX_APPLICATION]; /* Application ID */
82 guint8 ignored7[1346];
83 };
84
85 /* the PrimaryVolumeDescriptor struct must exactly 2048 bytes long
86 * since we expect the supplementary volume descriptor to be right
87 * after it.
88 */
89 G_STATIC_ASSERT(sizeof(struct _PrimaryVolumeDescriptor) == 2048);
90
91 typedef struct _SupplementaryVolumeDescriptor SupplementaryVolumeDescriptor;
92
93 struct _SupplementaryVolumeDescriptor {
94 guint8 ignored[7];
95 gchar system[MAX_SYSTEM]; /* System ID */
96 };
97
98 typedef struct _SearchPPCBootinfoAsyncData SearchPPCBootinfoAsyncData;
99 struct _SearchPPCBootinfoAsyncData {
100 GTask *res;
101
102 PrimaryVolumeDescriptor *pvd;
103 guint8 *extent;
104
105 gchar **filepath;
106 gsize filepath_index;
107 gsize filepath_index_max;
108
109 gsize offset;
110 gsize length;
111 };
112
search_ppc_bootinfo_async_data_free(SearchPPCBootinfoAsyncData * data)113 static void search_ppc_bootinfo_async_data_free(SearchPPCBootinfoAsyncData *data)
114 {
115 g_object_unref(data->res);
116
117 g_strfreev(data->filepath);
118 g_free(data->extent);
119
120 g_slice_free(SearchPPCBootinfoAsyncData, data);
121
122 }
123
124 typedef struct _CreateFromLocationAsyncData CreateFromLocationAsyncData;
125 struct _CreateFromLocationAsyncData {
126 GFile *file;
127 SoupSession *session;
128 SoupMessage *message;
129 gchar *uri;
130
131 GTask *res;
132
133 PrimaryVolumeDescriptor pvd;
134 SupplementaryVolumeDescriptor svd;
135
136 gsize offset;
137 gsize length;
138
139 gchar *volume;
140 gchar *system;
141 gchar *application;
142 gchar *publisher;
143
144 guint flags;
145 gboolean bootable;
146 };
147
create_from_location_async_data_free(CreateFromLocationAsyncData * data)148 static void create_from_location_async_data_free
149 (CreateFromLocationAsyncData *data)
150 {
151 if (data->file != NULL)
152 g_object_unref(data->file);
153 if (data->session != NULL)
154 g_object_unref(data->session);
155 if (data->message != NULL)
156 g_object_unref(data->message);
157 g_object_unref(data->res);
158 g_free(data->volume);
159 g_free(data->system);
160 g_free(data->application);
161 g_free(data->publisher);
162
163 g_slice_free(CreateFromLocationAsyncData, data);
164 }
165
166 typedef struct _CreateFromLocationData CreateFromLocationData;
167 struct _CreateFromLocationData {
168 GMainLoop *main_loop;
169
170 GAsyncResult *res;
171 };
172
create_from_location_data_free(CreateFromLocationData * data)173 static void create_from_location_data_free(CreateFromLocationData *data)
174 {
175 g_object_unref(data->res);
176 g_main_loop_unref(data->main_loop);
177
178 g_slice_free(CreateFromLocationData, data);
179 }
180
181 GQuark
osinfo_media_error_quark(void)182 osinfo_media_error_quark(void)
183 {
184 static GQuark quark = 0;
185
186 if (!quark)
187 quark = g_quark_from_static_string("osinfo-media-error");
188
189 return quark;
190 }
191
192 /**
193 * SECTION:osinfo_media
194 * @short_description: An installation media for a (guest) OS
195 * @see_also: #OsinfoOs
196 *
197 * #OsinfoMedia is an entity representing an installation media
198 * a (guest) operating system.
199 */
200
201 struct _OsinfoMediaPrivate
202 {
203 GWeakRef os;
204 OsinfoInstallScriptList *scripts;
205 };
206
207 G_DEFINE_TYPE_WITH_PRIVATE(OsinfoMedia, osinfo_media, OSINFO_TYPE_ENTITY);
208
209 enum {
210 PROP_0,
211
212 PROP_ARCHITECTURE,
213 PROP_URL,
214 PROP_VOLUME_ID,
215 PROP_PUBLISHER_ID,
216 PROP_APPLICATION_ID,
217 PROP_SYSTEM_ID,
218 PROP_KERNEL_PATH,
219 PROP_INITRD_PATH,
220 PROP_INSTALLER,
221 PROP_LIVE,
222 PROP_INSTALLER_REBOOTS,
223 PROP_OS,
224 PROP_LANGUAGES,
225 PROP_VOLUME_SIZE,
226 PROP_EJECT_AFTER_INSTALL,
227 PROP_INSTALLER_SCRIPT,
228
229 LAST_PROP
230 };
231 static GParamSpec *properties[LAST_PROP];
232
233 static void
osinfo_media_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)234 osinfo_media_get_property(GObject *object,
235 guint property_id,
236 GValue *value,
237 GParamSpec *pspec)
238 {
239 OsinfoMedia *media = OSINFO_MEDIA(object);
240
241 switch (property_id) {
242 case PROP_ARCHITECTURE:
243 g_value_set_string(value,
244 osinfo_media_get_architecture(media));
245 break;
246
247 case PROP_URL:
248 g_value_set_string(value,
249 osinfo_media_get_url(media));
250 break;
251
252 case PROP_VOLUME_ID:
253 g_value_set_string(value,
254 osinfo_media_get_volume_id(media));
255 break;
256
257 case PROP_PUBLISHER_ID:
258 g_value_set_string(value,
259 osinfo_media_get_publisher_id(media));
260 break;
261
262 case PROP_APPLICATION_ID:
263 g_value_set_string(value,
264 osinfo_media_get_application_id(media));
265 break;
266
267 case PROP_SYSTEM_ID:
268 g_value_set_string(value,
269 osinfo_media_get_system_id(media));
270 break;
271
272 case PROP_KERNEL_PATH:
273 g_value_set_string(value,
274 osinfo_media_get_kernel_path(media));
275 break;
276
277 case PROP_INITRD_PATH:
278 g_value_set_string(value,
279 osinfo_media_get_initrd_path(media));
280 break;
281
282 case PROP_INSTALLER:
283 g_value_set_boolean(value,
284 osinfo_media_get_installer(media));
285 break;
286
287 case PROP_LIVE:
288 g_value_set_boolean(value,
289 osinfo_media_get_live(media));
290 break;
291
292 case PROP_INSTALLER_REBOOTS:
293 g_value_set_int(value,
294 osinfo_media_get_installer_reboots(media));
295 break;
296
297 case PROP_OS:
298 g_value_take_object(value, osinfo_media_get_os(media));
299 break;
300
301 case PROP_LANGUAGES:
302 g_value_set_pointer(value, osinfo_media_get_languages(media));
303 break;
304
305 case PROP_VOLUME_SIZE:
306 g_value_set_int64(value,
307 osinfo_media_get_volume_size(media));
308 break;
309
310 case PROP_EJECT_AFTER_INSTALL:
311 g_value_set_boolean(value,
312 osinfo_media_get_eject_after_install(media));
313 break;
314
315 case PROP_INSTALLER_SCRIPT:
316 g_value_set_boolean(value,
317 osinfo_media_supports_installer_script(media));
318 break;
319
320 default:
321 /* We don't have any other property... */
322 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
323 break;
324 }
325 }
326
327 static void
osinfo_media_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)328 osinfo_media_set_property(GObject *object,
329 guint property_id,
330 const GValue *value,
331 GParamSpec *pspec)
332 {
333 OsinfoMedia *media = OSINFO_MEDIA(object);
334
335 switch (property_id) {
336 case PROP_ARCHITECTURE:
337 osinfo_entity_set_param(OSINFO_ENTITY(media),
338 OSINFO_MEDIA_PROP_ARCHITECTURE,
339 g_value_get_string(value));
340 break;
341
342 case PROP_URL:
343 osinfo_entity_set_param(OSINFO_ENTITY(media),
344 OSINFO_MEDIA_PROP_URL,
345 g_value_get_string(value));
346 break;
347
348 case PROP_VOLUME_ID:
349 osinfo_entity_set_param(OSINFO_ENTITY(media),
350 OSINFO_MEDIA_PROP_VOLUME_ID,
351 g_value_get_string(value));
352 break;
353
354 case PROP_PUBLISHER_ID:
355 osinfo_entity_set_param(OSINFO_ENTITY(media),
356 OSINFO_MEDIA_PROP_PUBLISHER_ID,
357 g_value_get_string(value));
358 break;
359
360 case PROP_APPLICATION_ID:
361 osinfo_entity_set_param(OSINFO_ENTITY(media),
362 OSINFO_MEDIA_PROP_APPLICATION_ID,
363 g_value_get_string(value));
364 break;
365
366 case PROP_SYSTEM_ID:
367 osinfo_entity_set_param(OSINFO_ENTITY(media),
368 OSINFO_MEDIA_PROP_SYSTEM_ID,
369 g_value_get_string(value));
370 break;
371
372 case PROP_KERNEL_PATH:
373 osinfo_entity_set_param(OSINFO_ENTITY(media),
374 OSINFO_MEDIA_PROP_KERNEL,
375 g_value_get_string(value));
376 break;
377
378 case PROP_INITRD_PATH:
379 osinfo_entity_set_param(OSINFO_ENTITY(media),
380 OSINFO_MEDIA_PROP_INITRD,
381 g_value_get_string(value));
382 break;
383
384 case PROP_LIVE:
385 osinfo_entity_set_param_boolean(OSINFO_ENTITY(media),
386 OSINFO_MEDIA_PROP_LIVE,
387 g_value_get_boolean(value));
388 break;
389
390 case PROP_INSTALLER:
391 osinfo_entity_set_param_boolean(OSINFO_ENTITY(media),
392 OSINFO_MEDIA_PROP_INSTALLER,
393 g_value_get_boolean(value));
394 break;
395
396 case PROP_INSTALLER_REBOOTS:
397 osinfo_entity_set_param_int64(OSINFO_ENTITY(media),
398 OSINFO_MEDIA_PROP_INSTALLER_REBOOTS,
399 g_value_get_int(value));
400 break;
401
402 case PROP_OS:
403 osinfo_media_set_os(media, g_value_get_object(value));
404 break;
405
406 case PROP_LANGUAGES:
407 osinfo_media_set_languages(media, g_value_get_pointer(value));
408 break;
409
410 case PROP_VOLUME_SIZE:
411 osinfo_entity_set_param_int64(OSINFO_ENTITY(media),
412 OSINFO_MEDIA_PROP_VOLUME_SIZE,
413 g_value_get_int64(value));
414 break;
415
416 case PROP_EJECT_AFTER_INSTALL:
417 osinfo_entity_set_param_boolean(OSINFO_ENTITY(media),
418 OSINFO_MEDIA_PROP_EJECT_AFTER_INSTALL,
419 g_value_get_boolean(value));
420 break;
421
422 case PROP_INSTALLER_SCRIPT:
423 osinfo_entity_set_param_boolean(OSINFO_ENTITY(media),
424 OSINFO_MEDIA_PROP_INSTALLER_SCRIPT,
425 g_value_get_boolean(value));
426 break;
427
428 default:
429 /* We don't have any other property... */
430 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
431 break;
432 }
433 }
434
435 static void
osinfo_media_finalize(GObject * object)436 osinfo_media_finalize(GObject *object)
437 {
438 OsinfoMedia *media = OSINFO_MEDIA(object);
439
440 g_object_unref(media->priv->scripts);
441
442 /* Chain up to the parent class */
443 G_OBJECT_CLASS(osinfo_media_parent_class)->finalize(object);
444 }
445
osinfo_media_dispose(GObject * obj)446 static void osinfo_media_dispose(GObject *obj)
447 {
448 OsinfoMedia *media = OSINFO_MEDIA(obj);
449
450 g_weak_ref_clear(&media->priv->os);
451
452 G_OBJECT_CLASS(osinfo_media_parent_class)->dispose(obj);
453 }
454
455
456 /* Init functions */
457 static void
osinfo_media_class_init(OsinfoMediaClass * klass)458 osinfo_media_class_init(OsinfoMediaClass *klass)
459 {
460 GObjectClass *g_klass = G_OBJECT_CLASS(klass);
461
462 g_klass->dispose = osinfo_media_dispose;
463 g_klass->finalize = osinfo_media_finalize;
464 g_klass->get_property = osinfo_media_get_property;
465 g_klass->set_property = osinfo_media_set_property;
466
467 /**
468 * OsinfoMedia:architecture:
469 *
470 * The target hardware architecture of this media.
471 */
472 properties[PROP_ARCHITECTURE] = g_param_spec_string("architecture",
473 "ARCHITECTURE",
474 _("CPU Architecture"),
475 NULL /* default value */,
476 G_PARAM_READWRITE |
477 G_PARAM_STATIC_STRINGS);
478
479 /**
480 * OsinfoMedia:url:
481 *
482 * The URL to this media.
483 */
484 properties[PROP_URL] = g_param_spec_string("url",
485 "URL",
486 _("The URL to this media"),
487 NULL /* default value */,
488 G_PARAM_READWRITE |
489 G_PARAM_STATIC_STRINGS);
490
491 /**
492 * OsinfoMedia:volume-id:
493 *
494 * Expected volume ID (regular expression) for ISO9660 image/device.
495 */
496 properties[PROP_VOLUME_ID] = g_param_spec_string("volume-id",
497 "VolumeID",
498 _("The expected ISO9660 volume ID"),
499 NULL /* default value */,
500 G_PARAM_READWRITE |
501 G_PARAM_STATIC_STRINGS);
502
503 /**
504 * OsinfoMedia:publisher-id:
505 *
506 * Expected publisher ID (regular expression) for ISO9660 image/device.
507 */
508 properties[PROP_PUBLISHER_ID] = g_param_spec_string("publisher-id",
509 "PublisherID",
510 _("The expected ISO9660 publisher ID"),
511 NULL /* default value */,
512 G_PARAM_READWRITE |
513 G_PARAM_STATIC_STRINGS);
514
515 /**
516 * OsinfoMedia:application-id:
517 *
518 * Expected application ID (regular expression) for ISO9660 image/device.
519 */
520 properties[PROP_APPLICATION_ID] = g_param_spec_string("application-id",
521 "ApplicationID",
522 _("The expected ISO9660 application ID"),
523 NULL /* default value */,
524 G_PARAM_READWRITE |
525 G_PARAM_STATIC_STRINGS);
526
527 /**
528 * OsinfoMedia:system-id:
529 *
530 * Expected system ID (regular expression) for ISO9660 image/device.
531 */
532 properties[PROP_SYSTEM_ID] = g_param_spec_string("system-id",
533 "SystemID",
534 _("The expected ISO9660 system ID"),
535 NULL /* default value */,
536 G_PARAM_READWRITE |
537 G_PARAM_STATIC_STRINGS);
538
539 /**
540 * OsinfoMedia:kernel-path:
541 *
542 * The path to the kernel image in the install tree.
543 */
544 properties[PROP_KERNEL_PATH] = g_param_spec_string("kernel-path",
545 "KernelPath",
546 _("The path to the kernel image"),
547 NULL /* default value */,
548 G_PARAM_READWRITE |
549 G_PARAM_STATIC_STRINGS);
550
551 /**
552 * OsinfoMedia:initrd-path:
553 *
554 * The path to the initrd image in the install tree.
555 */
556 properties[PROP_INITRD_PATH] = g_param_spec_string("initrd-path",
557 "InitrdPath",
558 _("The path to the initrd image"),
559 NULL /* default value */,
560 G_PARAM_READWRITE |
561 G_PARAM_STATIC_STRINGS);
562
563 /**
564 * OsinfoMedia:installer:
565 *
566 * Whether media provides an installer for an OS.
567 */
568 properties[PROP_INSTALLER] = g_param_spec_boolean("installer",
569 "Installer",
570 _("Media provides an installer"),
571 TRUE /* default value */,
572 G_PARAM_READWRITE |
573 G_PARAM_STATIC_STRINGS);
574
575 /**
576 * OsinfoMedia:live:
577 *
578 * Whether media can boot directly an OS without any installations.
579 */
580 properties[PROP_LIVE] = g_param_spec_boolean("live",
581 "Live",
582 _("Media can boot directly w/o installation"),
583 FALSE /* default value */,
584 G_PARAM_READWRITE |
585 G_PARAM_STATIC_STRINGS);
586
587 /**
588 * OsinfoMedia:installer-reboots:
589 *
590 * If media is an installer, this property indicates the number of reboots
591 * the installer takes before installation is complete.
592 *
593 * This property is not applicable to media that has no installer. You can
594 * use #osinfo_media_get_installer(or OsinfoMedia::installer) to check
595 * that.
596 *
597 * Warning: Some media allow you to install from live sessions, in which
598 * case number of reboots *alone* is not a reliable method for tracking
599 * installation.
600 */
601 properties[PROP_INSTALLER_REBOOTS] = g_param_spec_int("installer-reboots",
602 "InstallerReboots",
603 _("Number of installer reboots"),
604 G_MININT,
605 G_MAXINT,
606 1 /* default value */,
607 G_PARAM_READWRITE |
608 G_PARAM_STATIC_STRINGS);
609
610 /**
611 * OsinfoMedia:os:
612 *
613 * Os information for the current media. For media stored in an
614 * #OsinfoDb, it will be filled when the database is loaded, otherwise
615 * the property will be filled after a successful call to
616 * osinfo_db_identify_media().
617 */
618 properties[PROP_OS] = g_param_spec_object("os",
619 "Os",
620 _("Information about the operating system on this media"),
621 OSINFO_TYPE_OS,
622 G_PARAM_READWRITE |
623 G_PARAM_STATIC_STRINGS);
624
625 /**
626 * OsinfoMedia:languages: (type GLib.List(utf8)) (transfer container):
627 *
628 * If media is an installer, this property indicates the languages that
629 * can be used during automatic installations.
630 *
631 * On media that are not installers, this property will indicate the
632 * languages that the user interface can be displayed in.
633 * Use #osinfo_media_get_installer(or OsinfoMedia::installer) to know
634 * if the media is an installer or not.
635 */
636 properties[PROP_LANGUAGES] = g_param_spec_pointer("languages",
637 "Languages",
638 _("Supported languages"),
639 G_PARAM_READABLE |
640 G_PARAM_STATIC_STRINGS);
641
642 /**
643 * OsinfoMedia:volume-size:
644 *
645 * Expected volume size, in bytes for ISO9660 image/device.
646 */
647 properties[PROP_VOLUME_SIZE] = g_param_spec_int64("volume-size",
648 "VolumeSize",
649 _("Expected ISO9660 volume size, in bytes"),
650 G_MININT,
651 G_MAXINT64,
652 -1 /* default value */,
653 G_PARAM_READWRITE |
654 G_PARAM_STATIC_STRINGS);
655
656 /**
657 * OsinfoMedia:eject-after-install:
658 *
659 * Whether the media should be ejected after the installation process.
660 *
661 * Some distros need their media to not be ejected after the final reboot
662 * during its installation process as some packages are installed after the
663 * reboot (which may cause the media to be ejected, depending on the
664 * application).
665 */
666 properties[PROP_EJECT_AFTER_INSTALL] = g_param_spec_boolean("eject-after-install",
667 "EjectAfterInstall",
668 _("Whether the media should be ejected after the installation process"),
669 TRUE /* default value */,
670 G_PARAM_READWRITE |
671 G_PARAM_STATIC_STRINGS);
672
673 /**
674 * OsinfoMedia:installer-script:
675 *
676 * Whether the media supports installation via an install-script.
677 *
678 * Some distros provide a few different medias and not all the medias support
679 * installation via an install script.
680 */
681 properties[PROP_INSTALLER_SCRIPT] = g_param_spec_boolean("installer-script",
682 "InstallerScript",
683 _("Whether the media should be used for an installation using install scripts"),
684 TRUE /* default value */,
685 G_PARAM_READWRITE |
686 G_PARAM_STATIC_STRINGS);
687
688 g_object_class_install_properties(g_klass, LAST_PROP, properties);
689 }
690
691 static void
osinfo_media_init(OsinfoMedia * media)692 osinfo_media_init(OsinfoMedia *media)
693 {
694 media->priv = osinfo_media_get_instance_private(media);
695 g_weak_ref_init(&media->priv->os, NULL);
696 media->priv->scripts = osinfo_install_scriptlist_new();
697 }
698
osinfo_media_new(const gchar * id,const gchar * architecture)699 OsinfoMedia *osinfo_media_new(const gchar *id,
700 const gchar *architecture)
701 {
702 OsinfoMedia *media;
703
704 media = g_object_new(OSINFO_TYPE_MEDIA,
705 "id", id,
706 NULL);
707
708 osinfo_entity_set_param(OSINFO_ENTITY(media),
709 OSINFO_MEDIA_PROP_ARCHITECTURE,
710 architecture);
711
712 return media;
713 }
714
on_media_create_from_location_ready(GObject * source_object,GAsyncResult * res,gpointer user_data)715 static void on_media_create_from_location_ready(GObject *source_object,
716 GAsyncResult *res,
717 gpointer user_data)
718 {
719 CreateFromLocationData *data = (CreateFromLocationData *)user_data;
720
721 data->res = g_object_ref(res);
722
723 g_main_loop_quit(data->main_loop);
724 }
725
726 /**
727 * osinfo_media_create_from_location:
728 * @location: the location of an installation media
729 * @cancellable: (allow-none): a #GCancellable, or %NULL
730 * @error: The location where to store any error, or %NULL
731 *
732 * Creates a new #OsinfoMedia for installation media at @location. The @location
733 * could be a http:// or a https:// URI or a local path.
734 *
735 * NOTE: Currently this only works for ISO images/devices.
736 *
737 * Returns: (transfer full): a new #OsinfoMedia , or NULL on error
738 */
osinfo_media_create_from_location(const gchar * location,GCancellable * cancellable,GError ** error)739 OsinfoMedia *osinfo_media_create_from_location(const gchar *location,
740 GCancellable *cancellable,
741 GError **error)
742 {
743 return osinfo_media_create_from_location_with_flags(location,
744 cancellable,
745 OSINFO_MEDIA_DETECT_REQUIRE_BOOTABLE,
746 error);
747 }
748
749 /**
750 * osinfo_media_create_from_location_with_flags:
751 * @location: the location of an installation media
752 * @cancellable: (allow-none): a #GCancellable, or %NULL
753 * @error: The location where to store any error, or %NULL
754 * @flags: An #OsinfoMediaDetectFlag, or 0.
755 *
756 * Creates a new #OsinfoMedia for installation media at @location. The @location
757 * could be a http:// or a https:// URI or a local path.
758 *
759 * NOTE: Currently this only works for ISO images/devices.
760 *
761 * Returns: (transfer full): a new #OsinfoMedia , or NULL on error
762 *
763 * Since: 1.6.0
764 */
osinfo_media_create_from_location_with_flags(const gchar * location,GCancellable * cancellable,guint flags,GError ** error)765 OsinfoMedia *osinfo_media_create_from_location_with_flags(const gchar *location,
766 GCancellable *cancellable,
767 guint flags,
768 GError **error)
769 {
770 CreateFromLocationData *data;
771 OsinfoMedia *ret;
772
773 data = g_slice_new0(CreateFromLocationData);
774 data->main_loop = g_main_loop_new(g_main_context_get_thread_default(),
775 FALSE);
776
777 osinfo_media_create_from_location_with_flags_async(location,
778 G_PRIORITY_DEFAULT,
779 cancellable,
780 on_media_create_from_location_ready,
781 flags,
782 data);
783
784 /* Loop till we get a reply (or time out) */
785 g_main_loop_run(data->main_loop);
786
787 ret = osinfo_media_create_from_location_with_flags_finish(data->res, error);
788 create_from_location_data_free(data);
789
790 return ret;
791 }
792
is_str_empty(const gchar * str)793 static gboolean is_str_empty(const gchar *str) {
794 guint8 i;
795 gboolean ret = TRUE;
796
797 if ((str == NULL) || (*str == 0))
798 return TRUE;
799
800 for (i = 0; i < strlen(str); i++)
801 if (!g_ascii_isspace(str[i])) {
802 ret = FALSE;
803
804 break;
805 }
806
807 return ret;
808 }
809
set_non_bootable_media_error(GError ** error)810 static void set_non_bootable_media_error(GError **error)
811 {
812 g_set_error(error,
813 OSINFO_MEDIA_ERROR,
814 OSINFO_MEDIA_ERROR_NOT_BOOTABLE,
815 _("Install media is not bootable"));
816 }
817
818 static OsinfoMedia *
create_from_location_async_data(CreateFromLocationAsyncData * data)819 create_from_location_async_data(CreateFromLocationAsyncData *data)
820 {
821 OsinfoMedia *media;
822 guint64 vol_size;
823 guint8 index;
824
825 media = g_object_new(OSINFO_TYPE_MEDIA,
826 "id", data->uri,
827 NULL);
828 osinfo_entity_set_param(OSINFO_ENTITY(media),
829 OSINFO_MEDIA_PROP_URL,
830 data->uri);
831 if (!is_str_empty(data->volume))
832 osinfo_entity_set_param(OSINFO_ENTITY(media),
833 OSINFO_MEDIA_PROP_VOLUME_ID,
834 data->volume);
835 if (!is_str_empty(data->system))
836 osinfo_entity_set_param(OSINFO_ENTITY(media),
837 OSINFO_MEDIA_PROP_SYSTEM_ID,
838 data->system);
839 if (!is_str_empty(data->publisher))
840 osinfo_entity_set_param(OSINFO_ENTITY(media),
841 OSINFO_MEDIA_PROP_PUBLISHER_ID,
842 data->publisher);
843 if (!is_str_empty(data->application))
844 osinfo_entity_set_param(OSINFO_ENTITY(media),
845 OSINFO_MEDIA_PROP_APPLICATION_ID,
846 data->application);
847
848 index = (G_BYTE_ORDER == G_LITTLE_ENDIAN) ? 0 : 1;
849 vol_size = ((gint64) data->pvd.volume_space_size[index]) *
850 data->pvd.logical_blk_size[index];
851 osinfo_entity_set_param_int64(OSINFO_ENTITY(media),
852 OSINFO_MEDIA_PROP_VOLUME_SIZE,
853 vol_size);
854
855 osinfo_entity_set_param_boolean(OSINFO_ENTITY(media),
856 OSINFO_MEDIA_PROP_BOOTABLE,
857 data->bootable);
858
859 return media;
860 }
861
check_directory_record_entry_flags(guint8 flags,gboolean is_dir)862 static gboolean check_directory_record_entry_flags(guint8 flags,
863 gboolean is_dir)
864 {
865 if (is_dir)
866 return (flags & DIRECTORY_RECORD_FLAG_DIRECTORY) != 0;
867
868 return (flags & DIRECTORY_RECORD_FLAG_DIRECTORY) == 0;
869 }
870
on_directory_record_extent_read(GObject * source,GAsyncResult * res,gpointer user_data)871 static void on_directory_record_extent_read(GObject *source,
872 GAsyncResult *res,
873 gpointer user_data)
874 {
875 GInputStream *stream = G_INPUT_STREAM(source);
876 SearchPPCBootinfoAsyncData *data;
877 DirectoryRecord *dr;
878 gsize offset;
879 gssize ret;
880 gboolean is_dir;
881 guint8 index = (G_BYTE_ORDER == G_LITTLE_ENDIAN) ? 0 : 1;
882 GError *error = NULL;
883
884 data = (SearchPPCBootinfoAsyncData *)user_data;
885
886 ret = g_input_stream_read_finish(stream, res, &error);
887 if (ret < 0) {
888 g_prefix_error(&error,
889 _("Failed to read \"%s\" directory record extent: "),
890 data->filepath[data->filepath_index]);
891 goto cleanup;
892 }
893
894 if (ret == 0) {
895 g_set_error(&error,
896 OSINFO_MEDIA_ERROR,
897 OSINFO_MEDIA_ERROR_NO_DIRECTORY_RECORD_EXTENT,
898 _("No \"%s\" directory record extent"),
899 data->filepath[data->filepath_index]);
900 goto cleanup;
901 }
902
903 data->offset += ret;
904 if (data->offset < data->length) {
905 g_input_stream_read_async(stream,
906 ((gchar *)data->extent + data->offset),
907 data->length - data->offset,
908 g_task_get_priority(data->res),
909 g_task_get_cancellable(data->res),
910 on_directory_record_extent_read,
911 data);
912 return;
913 }
914
915
916 is_dir = data->filepath_index < data->filepath_index_max - 1;
917 offset = 0;
918
919 do {
920 gboolean check;
921
922 dr = (DirectoryRecord *)&data->extent[offset];
923 if (dr->length == 0) {
924 offset++;
925 continue;
926 }
927
928 check = check_directory_record_entry_flags(dr->flags, is_dir);
929 if (check &&
930 g_ascii_strncasecmp(data->filepath[data->filepath_index], dr->filename, strlen(data->filepath[data->filepath_index])) == 0) {
931 data->filepath_index++;
932 break;
933 }
934
935 offset += dr->length;
936 } while (offset < data->length);
937
938 if (offset >= data->length) {
939 set_non_bootable_media_error(&error);
940 goto cleanup;
941 }
942
943 /* It just means that we walked through all the filepath entries and we
944 * found the file we're looking for! Just return TRUE! */
945 if (data->filepath_index == data->filepath_index_max)
946 goto cleanup;
947
948 if (!G_IS_SEEKABLE(stream) ||
949 !g_seekable_seek(G_SEEKABLE(stream),
950 dr->extent_location[index] * data->pvd->logical_blk_size[index],
951 G_SEEK_SET,
952 g_task_get_cancellable(data->res),
953 &error))
954 goto cleanup;
955
956 data->offset = 0;
957 data->length = dr->extent_size[index];
958
959 g_free(data->extent);
960 data->extent = g_malloc0(data->length);
961 g_input_stream_read_async(stream,
962 data->extent,
963 data->length,
964 g_task_get_priority(data->res),
965 g_task_get_cancellable(data->res),
966 on_directory_record_extent_read,
967 data);
968 return;
969
970 cleanup:
971 if (error != NULL)
972 g_task_return_error(data->res, error);
973 else
974 g_task_return_boolean(data->res, TRUE);
975
976 search_ppc_bootinfo_async_data_free(data);
977 }
978
search_ppc_bootinfo_async(GInputStream * stream,PrimaryVolumeDescriptor * pvd,gint priority,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)979 static void search_ppc_bootinfo_async(GInputStream *stream,
980 PrimaryVolumeDescriptor *pvd,
981 gint priority,
982 GCancellable *cancellable,
983 GAsyncReadyCallback callback,
984 gpointer user_data)
985 {
986 SearchPPCBootinfoAsyncData *data;
987 DirectoryRecord *root_directory_entry = NULL;
988 GError *error = NULL;
989 guint8 index = (G_BYTE_ORDER == G_LITTLE_ENDIAN) ? 0 : 1;
990
991 g_return_if_fail(G_IS_INPUT_STREAM(stream));
992 g_return_if_fail(pvd != NULL);
993
994 data = g_slice_new0(SearchPPCBootinfoAsyncData);
995 data->pvd = pvd;
996 data->res = g_task_new(stream,
997 cancellable,
998 callback,
999 user_data);
1000 g_task_set_priority(data->res, priority);
1001
1002 root_directory_entry = (DirectoryRecord *)&data->pvd->root_directory_entry;
1003
1004 if (!G_IS_SEEKABLE(stream) ||
1005 !g_seekable_seek(G_SEEKABLE(stream),
1006 root_directory_entry->extent_location[index] * data->pvd->logical_blk_size[index],
1007 G_SEEK_SET,
1008 g_task_get_cancellable(data->res),
1009 &error))
1010 goto cleanup;
1011
1012 data->offset = 0;
1013 data->length = root_directory_entry->extent_size[index];
1014 data->extent = g_malloc0(root_directory_entry->extent_size[index]);
1015
1016 data->filepath = g_strsplit(PPC_BOOTINFO, "/", -1);
1017 /* As the path starts with "/", we can just ignore the first element of the
1018 * split entry. */
1019 data->filepath_index = 1;
1020 data->filepath_index_max = g_strv_length(data->filepath);
1021
1022 g_input_stream_read_async(stream,
1023 data->extent,
1024 data->length,
1025 g_task_get_priority(data->res),
1026 g_task_get_cancellable(data->res),
1027 on_directory_record_extent_read,
1028 data);
1029 return;
1030
1031 cleanup:
1032 g_task_return_error(data->res, error);
1033 search_ppc_bootinfo_async_data_free(data);
1034 }
1035
search_ppc_bootinfo_finish(GAsyncResult * res,GError ** error)1036 static gboolean search_ppc_bootinfo_finish(GAsyncResult *res,
1037 GError **error)
1038 {
1039 GTask *task = G_TASK(res);
1040
1041 g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
1042
1043 return g_task_propagate_boolean(task, error);
1044 }
1045
search_ppc_bootinfo_callback(GObject * source,GAsyncResult * res,gpointer user_data)1046 static void search_ppc_bootinfo_callback(GObject *source,
1047 GAsyncResult *res,
1048 gpointer user_data)
1049 {
1050 OsinfoMedia *media = NULL;
1051 GInputStream *stream = G_INPUT_STREAM(source);
1052 GError *error = NULL;
1053 CreateFromLocationAsyncData *data;
1054 gboolean ret;
1055
1056 data = (CreateFromLocationAsyncData *)user_data;
1057
1058 data->bootable = TRUE;
1059 ret = search_ppc_bootinfo_finish(res, &error);
1060 if (!ret) {
1061 if (g_error_matches(error,
1062 OSINFO_MEDIA_ERROR,
1063 OSINFO_MEDIA_ERROR_NOT_BOOTABLE)) {
1064 if ((data->flags & OSINFO_MEDIA_DETECT_REQUIRE_BOOTABLE) != 0) {
1065 goto cleanup;
1066 } else {
1067 g_clear_error(&error);
1068 data->bootable = FALSE;
1069 }
1070 }
1071 }
1072
1073 media = create_from_location_async_data(data);
1074
1075 cleanup:
1076 if (error != NULL)
1077 g_task_return_error(data->res, error);
1078 else
1079 g_task_return_pointer(data->res, media, g_object_unref);
1080
1081 g_object_unref(stream);
1082 create_from_location_async_data_free(data);
1083 }
1084
on_svd_read(GObject * source,GAsyncResult * res,gpointer user_data)1085 static void on_svd_read(GObject *source,
1086 GAsyncResult *res,
1087 gpointer user_data)
1088 {
1089 OsinfoMedia *media = NULL;
1090 GInputStream *stream = G_INPUT_STREAM(source);
1091 GError *error = NULL;
1092 CreateFromLocationAsyncData *data;
1093 gssize ret;
1094
1095 data = (CreateFromLocationAsyncData *)user_data;
1096
1097 ret = g_input_stream_read_finish(stream,
1098 res,
1099 &error);
1100 if (ret < 0) {
1101 g_prefix_error(&error,
1102 _("Failed to read supplementary volume descriptor: "));
1103 goto cleanup;
1104 }
1105 if (ret == 0) {
1106 g_set_error(&error,
1107 OSINFO_MEDIA_ERROR,
1108 OSINFO_MEDIA_ERROR_NO_SVD,
1109 _("Supplementary volume descriptor was truncated"));
1110 goto cleanup;
1111 }
1112
1113 data->offset += ret;
1114 if (data->offset < data->length) {
1115 g_input_stream_read_async(stream,
1116 ((gchar *)&data->svd + data->offset),
1117 data->length - data->offset,
1118 g_task_get_priority(data->res),
1119 g_task_get_cancellable(data->res),
1120 on_svd_read,
1121 data);
1122 return;
1123 }
1124
1125
1126 data->svd.system[MAX_SYSTEM - 1] = 0;
1127 g_strchomp(data->svd.system);
1128
1129 if (strncmp(BOOTABLE_TAG, data->svd.system, sizeof(BOOTABLE_TAG)) != 0) {
1130 /*
1131 * In case we reached this point, there are basically 2 alternatives:
1132 * - the media is a PPC media and we should check for the existence of
1133 * "/ppc/bootinfo.txt" file
1134 * - the media is not bootable.
1135 *
1136 * Let's check for the existence of the "/ppc/bootinfo.txt" file and,
1137 * only after that, return whether the media is bootable or not.
1138 */
1139 search_ppc_bootinfo_async(stream,
1140 &data->pvd,
1141 g_task_get_priority(data->res),
1142 g_task_get_cancellable(data->res),
1143 search_ppc_bootinfo_callback,
1144 data);
1145 return;
1146 }
1147
1148 data->bootable = TRUE;
1149 media = create_from_location_async_data(data);
1150
1151 cleanup:
1152 if (error != NULL)
1153 g_task_return_error(data->res, error);
1154 else
1155 g_task_return_pointer(data->res, media, g_object_unref);
1156
1157 g_object_unref(stream);
1158 create_from_location_async_data_free(data);
1159 }
1160
on_pvd_read(GObject * source,GAsyncResult * res,gpointer user_data)1161 static void on_pvd_read(GObject *source,
1162 GAsyncResult *res,
1163 gpointer user_data)
1164 {
1165 GInputStream *stream = G_INPUT_STREAM(source);
1166 CreateFromLocationAsyncData *data;
1167 GError *error = NULL;
1168 gssize ret;
1169
1170 data = (CreateFromLocationAsyncData *)user_data;
1171
1172 ret = g_input_stream_read_finish(stream,
1173 res,
1174 &error);
1175 if (ret < 0) {
1176 g_prefix_error(&error, _("Failed to read primary volume descriptor: "));
1177 goto error;
1178 }
1179 if (ret == 0) {
1180 g_set_error(&error,
1181 OSINFO_MEDIA_ERROR,
1182 OSINFO_MEDIA_ERROR_NO_PVD,
1183 _("Primary volume descriptor was truncated"));
1184 goto error;
1185 }
1186
1187 data->offset += ret;
1188 if (data->offset < data->length) {
1189 g_input_stream_read_async(stream,
1190 ((gchar*)&data->pvd) + data->offset,
1191 data->length - data->offset,
1192 g_task_get_priority(data->res),
1193 g_task_get_cancellable(data->res),
1194 on_pvd_read,
1195 data);
1196 return;
1197 }
1198
1199 data->volume = g_strndup(data->pvd.volume, MAX_VOLUME);
1200 g_strchomp(data->volume);
1201
1202 data->system = g_strndup(data->pvd.system, MAX_SYSTEM);
1203 g_strchomp(data->system);
1204
1205 data->publisher = g_strndup(data->pvd.publisher, MAX_PUBLISHER);
1206 g_strchomp(data->publisher);
1207
1208 data->application = g_strndup(data->pvd.application, MAX_APPLICATION);
1209 g_strchomp(data->application);
1210
1211 if (is_str_empty(data->volume)) {
1212 g_set_error(&error,
1213 OSINFO_MEDIA_ERROR,
1214 OSINFO_MEDIA_ERROR_INSUFFICIENT_METADATA,
1215 _("Insufficient metadata on installation media"));
1216
1217 goto error;
1218 }
1219
1220 data->offset = 0;
1221 data->length = sizeof(data->svd);
1222
1223 g_input_stream_read_async(stream,
1224 (gchar *)&data->svd,
1225 data->length,
1226 g_task_get_priority(data->res),
1227 g_task_get_cancellable(data->res),
1228 on_svd_read,
1229 data);
1230 return;
1231
1232 error:
1233 g_object_unref(stream);
1234 g_task_return_error(data->res, error);
1235 create_from_location_async_data_free(data);
1236 }
1237
on_location_skipped(GObject * source,GAsyncResult * res,gpointer user_data)1238 static void on_location_skipped(GObject *source,
1239 GAsyncResult *res,
1240 gpointer user_data)
1241 {
1242 GInputStream *stream = G_INPUT_STREAM(source);
1243 CreateFromLocationAsyncData *data;
1244 GError *error = NULL;
1245
1246 data = (CreateFromLocationAsyncData *)user_data;
1247
1248 if (g_input_stream_skip_finish(stream, res, &error) < PVD_OFFSET) {
1249 if (error)
1250 g_prefix_error(&error, _("Failed to skip %d bytes"), PVD_OFFSET);
1251 else
1252 g_set_error(&error,
1253 OSINFO_MEDIA_ERROR,
1254 OSINFO_MEDIA_ERROR_NO_DESCRIPTORS,
1255 _("No volume descriptors"));
1256 g_object_unref(stream);
1257 g_task_return_error(data->res, error);
1258 create_from_location_async_data_free(data);
1259
1260 return;
1261 }
1262
1263 data->offset = 0;
1264 data->length = sizeof(data->pvd);
1265
1266 g_input_stream_read_async(stream,
1267 (gchar *)&data->pvd,
1268 data->length,
1269 g_task_get_priority(data->res),
1270 g_task_get_cancellable(data->res),
1271 on_pvd_read,
1272 data);
1273 }
1274
on_location_read(GObject * source,GAsyncResult * res,gpointer user_data)1275 static void on_location_read(GObject *source,
1276 GAsyncResult *res,
1277 gpointer user_data)
1278 {
1279 GInputStream *stream;
1280 CreateFromLocationAsyncData *data;
1281 GError *error = NULL;
1282
1283 data = (CreateFromLocationAsyncData *)user_data;
1284
1285 if (data->file != NULL) {
1286 stream = G_INPUT_STREAM(g_file_read_finish(G_FILE(source), res, &error));
1287 } else {
1288 stream = soup_session_send_finish(SOUP_SESSION(source), res, &error);
1289 if (!SOUP_STATUS_IS_SUCCESSFUL(data->message->status_code) && error == NULL) {
1290 g_set_error_literal(&error,
1291 OSINFO_MEDIA_ERROR,
1292 OSINFO_MEDIA_ERROR_NO_DESCRIPTORS,
1293 soup_status_get_phrase(data->message->status_code));
1294 }
1295 }
1296 if (error != NULL) {
1297 g_prefix_error(&error, _("Failed to open file: "));
1298 g_task_return_error(data->res, error);
1299 create_from_location_async_data_free(data);
1300
1301 return;
1302 }
1303
1304 g_input_stream_skip_async(stream,
1305 PVD_OFFSET,
1306 g_task_get_priority(data->res),
1307 g_task_get_cancellable(data->res),
1308 on_location_skipped,
1309 data);
1310 }
1311
1312 /**
1313 * osinfo_media_create_from_location_async:
1314 * @location: the location of an installation media
1315 * @priority: the I/O priority of the request
1316 * @cancellable: (allow-none): a #GCancellable, or %NULL
1317 * @callback: Function to call when result of this call is ready
1318 * @user_data: The user data to pass to @callback, or %NULL
1319 *
1320 * Asynchronous variant of #osinfo_media_create_from_location.
1321 */
osinfo_media_create_from_location_async(const gchar * location,gint priority,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)1322 void osinfo_media_create_from_location_async(const gchar *location,
1323 gint priority,
1324 GCancellable *cancellable,
1325 GAsyncReadyCallback callback,
1326 gpointer user_data)
1327 {
1328 osinfo_media_create_from_location_with_flags_async(location,
1329 priority,
1330 cancellable,
1331 callback,
1332 OSINFO_MEDIA_DETECT_REQUIRE_BOOTABLE,
1333 user_data);
1334 }
1335
1336 /**
1337 * osinfo_media_create_from_location_finish:
1338 * @res: a #GAsyncResult
1339 * @error: The location where to store any error, or %NULL
1340 *
1341 * Finishes an asynchronous media object creation process started with
1342 * #osinfo_media_create_from_location_async.
1343 *
1344 * Returns: (transfer full): a new #OsinfoMedia , or NULL on error
1345 *
1346 * Since: 1.6.0
1347 */
osinfo_media_create_from_location_finish(GAsyncResult * res,GError ** error)1348 OsinfoMedia *osinfo_media_create_from_location_finish(GAsyncResult *res,
1349 GError **error)
1350 {
1351 return osinfo_media_create_from_location_with_flags_finish(res, error);
1352 }
1353
1354 /**
1355 * osinfo_media_create_from_location_with_flags_async:
1356 * @location: the location of an installation media
1357 * @priority: the I/O priority of the request
1358 * @cancellable: (allow-none): a #GCancellable, or %NULL
1359 * @callback: Function to call when result of this call is ready
1360 * @flags: An #OsinfoMediaDetectFlag, or 0.
1361 * @user_data: The user data to pass to @callback, or %NULL
1362 *
1363 * Asynchronous variant of #osinfo_media_create_from_location_with_flags.
1364 *
1365 * Since: 1.6.0
1366 */
osinfo_media_create_from_location_with_flags_async(const gchar * location,gint priority,GCancellable * cancellable,GAsyncReadyCallback callback,guint flags,gpointer user_data)1367 void osinfo_media_create_from_location_with_flags_async(const gchar *location,
1368 gint priority,
1369 GCancellable *cancellable,
1370 GAsyncReadyCallback callback,
1371 guint flags,
1372 gpointer user_data)
1373 {
1374 CreateFromLocationAsyncData *data;
1375
1376 g_return_if_fail(location != NULL);
1377
1378 data = g_slice_new0(CreateFromLocationAsyncData);
1379 data->res = g_task_new(NULL,
1380 cancellable,
1381 callback,
1382 user_data);
1383 g_task_set_priority(data->res, priority);
1384 data->flags = flags;
1385
1386 data->uri = g_strdup(location);
1387
1388 if (osinfo_util_requires_soup(location)) {
1389 data->session = soup_session_new_with_options(
1390 SOUP_SESSION_USER_AGENT, "Wget/1.0",
1391 NULL);
1392 data->message = soup_message_new("GET", location);
1393
1394 soup_session_send_async(data->session,
1395 data->message,
1396 cancellable,
1397 on_location_read,
1398 data);
1399 } else {
1400 data->file = g_file_new_for_commandline_arg(location);
1401 g_file_read_async(data->file,
1402 priority,
1403 cancellable,
1404 on_location_read,
1405 data);
1406 }
1407 }
1408
1409 /**
1410 * osinfo_media_create_from_location_with_flags_finish:
1411 * @res: a #GAsyncResult
1412 * @error: The location where to store any error, or %NULL
1413 *
1414 * Finishes an asynchronous media object creation process started with
1415 * #osinfo_media_create_from_location_async.
1416 *
1417 * Returns: (transfer full): a new #OsinfoMedia , or NULL on error
1418 */
osinfo_media_create_from_location_with_flags_finish(GAsyncResult * res,GError ** error)1419 OsinfoMedia *osinfo_media_create_from_location_with_flags_finish(GAsyncResult *res,
1420 GError **error)
1421 {
1422 GTask *task = G_TASK(res);
1423
1424 g_return_val_if_fail(error == NULL || *error == NULL, NULL);
1425
1426 return g_task_propagate_pointer(task, error);
1427 }
1428
1429 /**
1430 * osinfo_media_get_architecture:
1431 * @media: an #OsinfoMedia instance
1432 *
1433 * Retrieves the target hardware architecture of the OS @media provides.
1434 *
1435 * Returns: (transfer none): the hardware architecture, or NULL
1436 */
osinfo_media_get_architecture(OsinfoMedia * media)1437 const gchar *osinfo_media_get_architecture(OsinfoMedia *media)
1438 {
1439 return osinfo_entity_get_param_value(OSINFO_ENTITY(media),
1440 OSINFO_MEDIA_PROP_ARCHITECTURE);
1441 }
1442
1443 /**
1444 * osinfo_media_get_url:
1445 * @media: an #OsinfoMedia instance
1446 *
1447 * The URL to the @media
1448 *
1449 * Returns: (transfer none): the URL, or NULL
1450 */
osinfo_media_get_url(OsinfoMedia * media)1451 const gchar *osinfo_media_get_url(OsinfoMedia *media)
1452 {
1453 return osinfo_entity_get_param_value(OSINFO_ENTITY(media),
1454 OSINFO_MEDIA_PROP_URL);
1455 }
1456
1457 /**
1458 * osinfo_media_get_volume_id:
1459 * @media: an #OsinfoMedia instance
1460 *
1461 * If @media is an ISO9660 image/device, this function retrieves the expected
1462 * volume ID.
1463 *
1464 * Note: In practice, this will usually not be the exact copy of the volume ID
1465 * string on the ISO image/device but rather a regular expression that matches
1466 * it.
1467 *
1468 * Returns: (transfer none): the volume id, or NULL
1469 */
osinfo_media_get_volume_id(OsinfoMedia * media)1470 const gchar *osinfo_media_get_volume_id(OsinfoMedia *media)
1471 {
1472 return osinfo_entity_get_param_value(OSINFO_ENTITY(media),
1473 OSINFO_MEDIA_PROP_VOLUME_ID);
1474 }
1475
1476 /**
1477 * osinfo_media_get_system_id:
1478 * @media: an #OsinfoMedia instance
1479 *
1480 * If @media is an ISO9660 image/device, this function retrieves the expected
1481 * system ID.
1482 *
1483 * Note: In practice, this will usually not be the exact copy of the system ID
1484 * string on the ISO image/device but rather a regular expression that matches
1485 * it.
1486 *
1487 * Returns: (transfer none): the system id, or NULL
1488 */
osinfo_media_get_system_id(OsinfoMedia * media)1489 const gchar *osinfo_media_get_system_id(OsinfoMedia *media)
1490 {
1491 return osinfo_entity_get_param_value(OSINFO_ENTITY(media),
1492 OSINFO_MEDIA_PROP_SYSTEM_ID);
1493 }
1494
1495 /**
1496 * osinfo_media_get_publisher_id:
1497 * @media: an #OsinfoMedia instance
1498 *
1499 * If @media is an ISO9660 image/device, this function retrieves the expected
1500 * publisher ID.
1501 *
1502 * Note: In practice, this will usually not be the exact copy of the publisher
1503 * ID string on the ISO image/device but rather a regular expression that
1504 * matches it.
1505 *
1506 * Returns: (transfer none): the publisher id, or NULL
1507 */
osinfo_media_get_publisher_id(OsinfoMedia * media)1508 const gchar *osinfo_media_get_publisher_id(OsinfoMedia *media)
1509 {
1510 return osinfo_entity_get_param_value(OSINFO_ENTITY(media),
1511 OSINFO_MEDIA_PROP_PUBLISHER_ID);
1512 }
1513
1514 /**
1515 * osinfo_media_get_application_id:
1516 * @media: an #OsinfoMedia instance
1517 *
1518 * If @media is an ISO9660 image/device, this function retrieves the expected
1519 * application ID.
1520 *
1521 * Note: In practice, this will usually not be the exact copy of the application
1522 * ID string on the ISO image/device but rather a regular expression that
1523 * matches it.
1524 *
1525 * Returns: (transfer none): the application id, or NULL
1526 */
osinfo_media_get_application_id(OsinfoMedia * media)1527 const gchar *osinfo_media_get_application_id(OsinfoMedia *media)
1528 {
1529 return osinfo_entity_get_param_value(OSINFO_ENTITY(media),
1530 OSINFO_MEDIA_PROP_APPLICATION_ID);
1531 }
1532
1533 /**
1534 * osinfo_media_get_kernel_path:
1535 * @media: an #OsinfoMedia instance
1536 *
1537 * Retrieves the path to the kernel image in the install tree.
1538 *
1539 * Note: This only applies to installer medias of 'linux' OS family.
1540 *
1541 * Returns: (transfer none): the path to kernel image, or NULL
1542 */
osinfo_media_get_kernel_path(OsinfoMedia * media)1543 const gchar *osinfo_media_get_kernel_path(OsinfoMedia *media)
1544 {
1545 return osinfo_entity_get_param_value(OSINFO_ENTITY(media),
1546 OSINFO_MEDIA_PROP_KERNEL);
1547 }
1548
1549 /**
1550 * osinfo_media_get_initrd_path:
1551 * @media: an #OsinfoMedia instance
1552 *
1553 * Retrieves the path to the initrd image in the install tree.
1554 *
1555 * Note: This only applies to installer medias of 'linux' OS family.
1556 *
1557 * Returns: (transfer none): the path to initrd image, or NULL
1558 */
osinfo_media_get_initrd_path(OsinfoMedia * media)1559 const gchar *osinfo_media_get_initrd_path(OsinfoMedia *media)
1560 {
1561 return osinfo_entity_get_param_value(OSINFO_ENTITY(media),
1562 OSINFO_MEDIA_PROP_INITRD);
1563 }
1564
1565 /**
1566 * osinfo_media_get_installer:
1567 * @media: an #OsinfoMedia instance
1568 *
1569 * Whether @media provides an installer for an OS.
1570 *
1571 * Returns: #TRUE if media is installer, #FALSE otherwise
1572 *
1573 * Since: 0.0.3
1574 */
osinfo_media_get_installer(OsinfoMedia * media)1575 gboolean osinfo_media_get_installer(OsinfoMedia *media)
1576 {
1577 return osinfo_entity_get_param_value_boolean_with_default
1578 (OSINFO_ENTITY(media), OSINFO_MEDIA_PROP_INSTALLER, TRUE);
1579 }
1580
1581 /**
1582 * osinfo_media_get_live:
1583 * @media: an #OsinfoMedia instance
1584 *
1585 * Whether @media can boot directly an OS without any installations.
1586 *
1587 * Returns: #TRUE if media is live, #FALSE otherwise
1588 *
1589 * Since: 0.0.3
1590 */
osinfo_media_get_live(OsinfoMedia * media)1591 gboolean osinfo_media_get_live(OsinfoMedia *media)
1592 {
1593 return osinfo_entity_get_param_value_boolean_with_default
1594 (OSINFO_ENTITY(media), OSINFO_MEDIA_PROP_LIVE, FALSE);
1595 }
1596
1597 /**
1598 * osinfo_media_get_installer_reboots:
1599 * @media: an #OsinfoMedia instance
1600 *
1601 * If media is an installer, this method retrieves the number of reboots the
1602 * installer takes before installation is complete.
1603 *
1604 * This function is not supposed to be called on media that has no installer.
1605 * You can use #osinfo_media_get_installer(or OsinfoMedia::installer) to check
1606 * that.
1607 *
1608 * Warning: Some media allow you to install from live sessions, in which case
1609 * number of reboots *alone* is not a reliable method for tracking installation.
1610 *
1611 * Returns: the number of installer reboots or -1 if media is not an installer
1612 *
1613 * Since: 0.2.1
1614 */
osinfo_media_get_installer_reboots(OsinfoMedia * media)1615 gint osinfo_media_get_installer_reboots(OsinfoMedia *media)
1616 {
1617 g_return_val_if_fail(OSINFO_IS_MEDIA(media), -1);
1618 g_return_val_if_fail(osinfo_media_get_installer(media), -1);
1619
1620 return (gint) osinfo_entity_get_param_value_int64_with_default
1621 (OSINFO_ENTITY(media), OSINFO_MEDIA_PROP_INSTALLER_REBOOTS, 1);
1622 }
1623
1624 /**
1625 * osinfo_media_get_os:
1626 * @media: an #OsinfoMedia instance
1627 *
1628 * Returns: (transfer full): the operating system, or NULL
1629 *
1630 * Since: 0.2.3
1631 */
osinfo_media_get_os(OsinfoMedia * media)1632 OsinfoOs *osinfo_media_get_os(OsinfoMedia *media)
1633 {
1634 g_return_val_if_fail(OSINFO_IS_MEDIA(media), NULL);
1635
1636 return g_weak_ref_get(&media->priv->os);
1637 }
1638
osinfo_media_set_os(OsinfoMedia * media,OsinfoOs * os)1639 void osinfo_media_set_os(OsinfoMedia *media, OsinfoOs *os)
1640 {
1641 g_return_if_fail(OSINFO_IS_MEDIA(media));
1642
1643 g_object_ref(os);
1644 g_weak_ref_set(&media->priv->os, os);
1645 g_object_unref(os);
1646 }
1647
1648 /**
1649 * osinfo_media_get_os_variants:
1650 * @media: an #OsinfoMedia instance
1651 *
1652 * Gets the variants of the associated operating system.
1653 *
1654 * Returns: (transfer full): the operating system variant, or NULL
1655 *
1656 * Since: 0.2.9
1657 */
osinfo_media_get_os_variants(OsinfoMedia * media)1658 OsinfoOsVariantList *osinfo_media_get_os_variants(OsinfoMedia *media)
1659 {
1660 OsinfoOs *os;
1661 OsinfoOsVariantList *os_variants;
1662 OsinfoOsVariantList *media_variants;
1663 GList *ids, *node;
1664 OsinfoFilter *filter;
1665
1666 g_return_val_if_fail(OSINFO_IS_MEDIA(media), NULL);
1667
1668 os = g_weak_ref_get(&media->priv->os);
1669 if (os == NULL)
1670 return NULL;
1671
1672 os_variants = osinfo_os_get_variant_list(os);
1673 g_object_unref(os);
1674
1675 ids = osinfo_entity_get_param_value_list(OSINFO_ENTITY(media),
1676 OSINFO_MEDIA_PROP_VARIANT);
1677 filter = osinfo_filter_new();
1678 media_variants = osinfo_os_variantlist_new();
1679 for (node = ids; node != NULL; node = node->next) {
1680 osinfo_filter_clear_constraints(filter);
1681 osinfo_filter_add_constraint(filter,
1682 OSINFO_ENTITY_PROP_ID,
1683 (const char *) node->data);
1684 osinfo_list_add_filtered(OSINFO_LIST(media_variants),
1685 OSINFO_LIST(os_variants),
1686 filter);
1687 }
1688 g_object_unref(os_variants);
1689
1690 return media_variants;
1691 }
1692
1693 /**
1694 * osinfo_media_get_languages:
1695 * @media: an #OsinfoMedia instance
1696 *
1697 * If media is an installer, this property indicates the languages that
1698 * can be used during automatic installations.
1699 *
1700 * On media that are not installers, this property will indicate the
1701 * languages that the user interface can be displayed in.
1702 * Use #osinfo_media_get_installer(or OsinfoMedia::installer) to know
1703 * if the media is an installer or not.
1704 *
1705 * Returns: (transfer container) (element-type utf8): a #GList
1706 * containing the list of the UI languages this media supports. The list
1707 * must be freed with g_list_free() when no longer needed. If the
1708 * supported languages are unknown, NULL will be returned.
1709 *
1710 * Since: 0.2.3
1711 */
osinfo_media_get_languages(OsinfoMedia * media)1712 GList *osinfo_media_get_languages(OsinfoMedia *media)
1713 {
1714 g_return_val_if_fail(OSINFO_IS_MEDIA(media), NULL);
1715 return osinfo_entity_get_param_value_list(OSINFO_ENTITY(media), OSINFO_MEDIA_PROP_LANG);
1716 }
1717
1718 /**
1719 * osinfo_media_set_languages:
1720 * @media: an #OsinfoMedia instance
1721 * @languages: (element-type utf8): a #GList containing the list of the UI
1722 * languages this media supports.
1723 *
1724 * Sets the #OSINFO_MEDIA_PROP_LANG parameter
1725 */
osinfo_media_set_languages(OsinfoMedia * media,GList * languages)1726 void osinfo_media_set_languages(OsinfoMedia *media, GList *languages)
1727 {
1728 GList *it;
1729
1730 g_return_if_fail(OSINFO_IS_MEDIA(media));
1731
1732 osinfo_entity_clear_param(OSINFO_ENTITY(media), OSINFO_MEDIA_PROP_LANG);
1733 for (it = languages; it != NULL; it = it->next)
1734 osinfo_entity_add_param(OSINFO_ENTITY(media),
1735 OSINFO_MEDIA_PROP_LANG,
1736 it->data);
1737 }
1738
1739 /**
1740 * osinfo_media_get_volume_size:
1741 * @media: an #OsinfoMedia instance
1742 *
1743 * Returns: the ISO9660 volume size, in bytes or -1 if size is
1744 * unknown or media is not an ISO9660 device/image.
1745 */
osinfo_media_get_volume_size(OsinfoMedia * media)1746 gint64 osinfo_media_get_volume_size(OsinfoMedia *media)
1747 {
1748 g_return_val_if_fail(OSINFO_IS_MEDIA(media), -1);
1749
1750 return osinfo_entity_get_param_value_int64_with_default
1751 (OSINFO_ENTITY(media), OSINFO_MEDIA_PROP_VOLUME_SIZE, -1);
1752 }
1753
1754 /**
1755 * osinfo_media_get_eject_after_install:
1756 * @media: an #OsinfoMedia instance
1757 *
1758 * Whether @media should ejected after the installation procces.
1759 *
1760 * Returns: #TRUE if media should be ejected, #FALSE otherwise
1761 *
1762 * Since: 0.2.13
1763 */
osinfo_media_get_eject_after_install(OsinfoMedia * media)1764 gboolean osinfo_media_get_eject_after_install(OsinfoMedia *media)
1765 {
1766 return osinfo_entity_get_param_value_boolean_with_default
1767 (OSINFO_ENTITY(media), OSINFO_MEDIA_PROP_EJECT_AFTER_INSTALL, TRUE);
1768 }
1769
1770 /**
1771 * osinfo_media_supports_installer_script:
1772 * @media: an #OsinfoMedia instance
1773 *
1774 * Whether @media supports installation using install scripts.
1775 *
1776 * Returns: #TRUE if install-scripts are supported by the media,
1777 * #FALSE otherwise
1778 *
1779 * Since: 1.3.0
1780 */
osinfo_media_supports_installer_script(OsinfoMedia * media)1781 gboolean osinfo_media_supports_installer_script(OsinfoMedia *media)
1782 {
1783 OsinfoOs *os;
1784 OsinfoInstallScriptList *list;
1785 gboolean ret;
1786
1787 g_return_val_if_fail(OSINFO_IS_MEDIA(media), FALSE);
1788
1789 os = osinfo_media_get_os(media);
1790 list = osinfo_os_get_install_script_list(os);
1791
1792 if (osinfo_list_get_length(OSINFO_LIST(list)) == 0 &&
1793 osinfo_list_get_length(OSINFO_LIST(media->priv->scripts)) == 0) {
1794 ret = FALSE;
1795 goto cleanup;
1796 }
1797
1798 ret = osinfo_entity_get_param_value_boolean_with_default
1799 (OSINFO_ENTITY(media), OSINFO_MEDIA_PROP_INSTALLER_SCRIPT, TRUE);
1800
1801 cleanup:
1802 g_object_unref(list);
1803 g_object_unref(os);
1804
1805 return ret;
1806 }
1807
1808 /**
1809 * osinfo_media_add_install_script:
1810 * @media: an #OsinfoMedia instance
1811 * @script: an #OsinfoInstallScript instance
1812 *
1813 * Adds an @script to the specified @media
1814 *
1815 * Since: 1.4.0
1816 */
osinfo_media_add_install_script(OsinfoMedia * media,OsinfoInstallScript * script)1817 void osinfo_media_add_install_script(OsinfoMedia *media, OsinfoInstallScript *script)
1818 {
1819 g_return_if_fail(OSINFO_IS_MEDIA(media));
1820
1821 osinfo_list_add(OSINFO_LIST(media->priv->scripts), OSINFO_ENTITY(script));
1822 }
1823
1824 /**
1825 * osinfo_media_get_install_script_list:
1826 * @media: an #OsinfoMedia instance
1827 *
1828 * Returns: (transfer full): a list of the install scripts for the specified media
1829 *
1830 * Since: 1.4.0
1831 */
osinfo_media_get_install_script_list(OsinfoMedia * media)1832 OsinfoInstallScriptList *osinfo_media_get_install_script_list(OsinfoMedia *media)
1833 {
1834 OsinfoList *new_list;
1835
1836 g_return_val_if_fail(OSINFO_IS_MEDIA(media), NULL);
1837 new_list = osinfo_list_new_copy(OSINFO_LIST(media->priv->scripts));
1838
1839 return OSINFO_INSTALL_SCRIPTLIST(new_list);
1840 }
1841
1842 /**
1843 * osinfo_media_is_bootable:
1844 * @media: and #OsinfoMedia instance
1845 *
1846 * Returns: #TRUE if the @media is bootable. #FALSE otherwise.
1847 *
1848 * Since: 1.6.0
1849 */
osinfo_media_is_bootable(OsinfoMedia * media)1850 gboolean osinfo_media_is_bootable(OsinfoMedia *media)
1851 {
1852 g_return_val_if_fail(OSINFO_IS_MEDIA(media), FALSE);
1853
1854 return osinfo_entity_get_param_value_boolean(OSINFO_ENTITY(media),
1855 OSINFO_MEDIA_PROP_BOOTABLE);
1856 }
1857