inspection: Deprecate APIs and remove support for inspecting installer CDs.

This just duplicated libosinfo information, and because it was never
tested it didn't work most of the time.
This commit is contained in:
Richard W.M. Jones
2017-06-16 10:30:33 +01:00
parent a0c1e6120c
commit 65cfecb0f5
33 changed files with 63 additions and 1708 deletions

View File

@@ -312,7 +312,6 @@ lib/handle.c
lib/hivex.c
lib/info.c
lib/inspect-apps.c
lib/inspect-fs-cd.c
lib/inspect-fs-unix.c
lib/inspect-fs-windows.c
lib/inspect-fs.c
@@ -330,7 +329,6 @@ lib/libvirt-is-version.c
lib/lpj.c
lib/match.c
lib/mountable.c
lib/osinfo.c
lib/private-data.c
lib/proto.c
lib/qemu.c

View File

@@ -563,73 +563,6 @@ as found by inspection of the guests configuration files.
If the hostname could not be determined, then the
string C<unknown> is returned.
Please read L<guestfs(3)/INSPECTION> for more details." };
{ defaults with
name = "inspect_get_format"; added = (1, 9, 4);
style = RString (RPlainString, "format"), [String (Mountable, "root")], [];
shortdesc = "get format of inspected operating system";
longdesc = "\
This returns the format of the inspected operating system. You
can use it to detect install images, live CDs and similar.
Currently defined formats are:
=over 4
=item \"installed\"
This is an installed operating system.
=item \"installer\"
The disk image being inspected is not an installed operating system,
but a I<bootable> install disk, live CD, or similar.
=item \"unknown\"
The format of this disk image is not known.
=back
Future versions of libguestfs may return other strings here.
The caller should be prepared to handle any string.
Please read L<guestfs(3)/INSPECTION> for more details." };
{ defaults with
name = "inspect_is_live"; added = (1, 9, 4);
style = RBool "live", [String (Mountable, "root")], [];
shortdesc = "get live flag for install disk";
longdesc = "\
If C<guestfs_inspect_get_format> returns C<installer> (this
is an install disk), then this returns true if a live image
was detected on the disk.
Please read L<guestfs(3)/INSPECTION> for more details." };
{ defaults with
name = "inspect_is_netinst"; added = (1, 9, 4);
style = RBool "netinst", [String (Mountable, "root")], [];
shortdesc = "get netinst (network installer) flag for install disk";
longdesc = "\
If C<guestfs_inspect_get_format> returns C<installer> (this
is an install disk), then this returns true if the disk is
a network installer, ie. not a self-contained install CD but
one which is likely to require network access to complete
the install.
Please read L<guestfs(3)/INSPECTION> for more details." };
{ defaults with
name = "inspect_is_multipart"; added = (1, 9, 4);
style = RBool "multipart", [String (Mountable, "root")], [];
shortdesc = "get multipart flag for install disk";
longdesc = "\
If C<guestfs_inspect_get_format> returns C<installer> (this
is an install disk), then this returns true if the disk is
part of a set.
Please read L<guestfs(3)/INSPECTION> for more details." };
{ defaults with

View File

@@ -119,6 +119,67 @@ If unavailable this is returned as an empty string C<\"\">.
=back
Please read L<guestfs(3)/INSPECTION> for more details." };
{ defaults with
name = "inspect_get_format"; added = (1, 9, 4);
style = RString (RPlainString, "format"), [String (Mountable, "root")], [];
deprecated_by = Deprecated_no_replacement;
shortdesc = "get format of inspected operating system";
longdesc = "\
Before libguestfs 1.38, there was some unreliable support for detecting
installer CDs. This API would return:
=over 4
=item \"installed\"
This is an installed operating system.
=item \"installer\"
The disk image being inspected is not an installed operating system,
but a I<bootable> install disk, live CD, or similar.
=item \"unknown\"
The format of this disk image is not known.
=back
In libguestfs E<ge> 1.38, this only returns C<installed>.
Use libosinfo directly to detect installer CDs.
Please read L<guestfs(3)/INSPECTION> for more details." };
{ defaults with
name = "inspect_is_live"; added = (1, 9, 4);
style = RBool "live", [String (Mountable, "root")], [];
deprecated_by = Deprecated_no_replacement;
shortdesc = "get live flag for install disk";
longdesc = "\
This is deprecated and always returns C<false>.
Please read L<guestfs(3)/INSPECTION> for more details." };
{ defaults with
name = "inspect_is_netinst"; added = (1, 9, 4);
style = RBool "netinst", [String (Mountable, "root")], [];
deprecated_by = Deprecated_no_replacement;
shortdesc = "get netinst (network installer) flag for install disk";
longdesc = "\
This is deprecated and always returns C<false>.
Please read L<guestfs(3)/INSPECTION> for more details." };
{ defaults with
name = "inspect_is_multipart"; added = (1, 9, 4);
style = RBool "multipart", [String (Mountable, "root")], [];
deprecated_by = Deprecated_no_replacement;
shortdesc = "get multipart flag for install disk";
longdesc = "\
This is deprecated and always returns C<false>.
Please read L<guestfs(3)/INSPECTION> for more details." };
]

View File

@@ -22,16 +22,7 @@ example_xml = \
example-fedora.xml \
example-rhel-6.xml \
example-ubuntu.xml \
example-windows.xml \
example-debian-netinst-cd.xml \
example-fedora-dvd.xml \
example-fedora-netinst-cd.xml \
example-rhel-6-dvd.xml \
example-rhel-6-netinst-cd.xml \
example-ubuntu-live-cd.xml \
example-windows-2003-x64-cd.xml \
example-windows-2003-x86-cd.xml \
example-windows-xp-cd.xml
example-windows.xml
EXTRA_DIST = \
expected-debian.img.xml \

View File

@@ -1,23 +0,0 @@
<?xml version="1.0"?>
<operatingsystems>
<operatingsystem>
<root>/dev/sda</root>
<name>linux</name>
<distro>debian</distro>
<product_name>Debian GNU/Linux 5.0.5 &quot;Lenny&quot; - Official amd64 NETINST Binary-1 20100627-10:37</product_name>
<major_version>5</major_version>
<minor_version>0</minor_version>
<format>installer</format>
<netinst/>
<mountpoints>
<mountpoint dev="/dev/sda">/</mountpoint>
</mountpoints>
<filesystems>
<filesystem dev="/dev/sda">
<type>iso9660</type>
<label>Debian 5.0.5 amd64 Bin-1</label>
</filesystem>
</filesystems>
<applications/>
</operatingsystem>
</operatingsystems>

View File

@@ -11,7 +11,6 @@
<package_format>deb</package_format>
<package_management>apt</package_management>
<hostname>debian5x64.home.annexia.org</hostname>
<format>installed</format>
<mountpoints>
<mountpoint dev="/dev/debian5x64.home.annexia.org/root">/</mountpoint>
<mountpoint dev="/dev/debian5x64.home.annexia.org/tmp">/tmp</mountpoint>

View File

@@ -1,23 +0,0 @@
<?xml version="1.0"?>
<operatingsystems>
<operatingsystem>
<root>/dev/sda</root>
<name>linux</name>
<arch>x86_64</arch>
<distro>fedora</distro>
<major_version>14</major_version>
<minor_version>0</minor_version>
<format>installer</format>
<multipart/>
<mountpoints>
<mountpoint dev="/dev/sda">/</mountpoint>
</mountpoints>
<filesystems>
<filesystem dev="/dev/sda">
<type>iso9660</type>
<label>Fedora 14 x86_64 DVD</label>
</filesystem>
</filesystems>
<applications/>
</operatingsystem>
</operatingsystems>

View File

@@ -1,21 +0,0 @@
<?xml version="1.0"?>
<operatingsystems>
<operatingsystem>
<root>/dev/sda</root>
<name>linux</name>
<distro>fedora</distro>
<major_version>14</major_version>
<minor_version>0</minor_version>
<format>installer</format>
<mountpoints>
<mountpoint dev="/dev/sda">/</mountpoint>
</mountpoints>
<filesystems>
<filesystem dev="/dev/sda">
<type>iso9660</type>
<label>Fedora</label>
</filesystem>
</filesystems>
<applications/>
</operatingsystem>
</operatingsystems>

View File

@@ -11,7 +11,6 @@
<package_format>rpm</package_format>
<package_management>yum</package_management>
<hostname>f18x64homeannexiaorg</hostname>
<format>installed</format>
<mountpoints>
<mountpoint dev="/dev/fedora/root">/</mountpoint>
<mountpoint dev="/dev/sda1">/boot</mountpoint>

View File

@@ -1,23 +0,0 @@
<?xml version="1.0"?>
<operatingsystems>
<operatingsystem>
<root>/dev/sda</root>
<name>linux</name>
<arch>x86_64</arch>
<distro>rhel</distro>
<major_version>6</major_version>
<minor_version>0</minor_version>
<format>installer</format>
<multipart/>
<mountpoints>
<mountpoint dev="/dev/sda">/</mountpoint>
</mountpoints>
<filesystems>
<filesystem dev="/dev/sda">
<type>iso9660</type>
<label>RHEL_6.0 x86_64 Disc 1</label>
</filesystem>
</filesystems>
<applications/>
</operatingsystem>
</operatingsystems>

View File

@@ -1,21 +0,0 @@
<?xml version="1.0"?>
<operatingsystems>
<operatingsystem>
<root>/dev/sda</root>
<name>linux</name>
<distro>rhel</distro>
<major_version>6</major_version>
<minor_version>0</minor_version>
<format>installer</format>
<mountpoints>
<mountpoint dev="/dev/sda">/</mountpoint>
</mountpoints>
<filesystems>
<filesystem dev="/dev/sda">
<type>iso9660</type>
<label>RHEL_6.0 x86_64 boot</label>
</filesystem>
</filesystems>
<applications/>
</operatingsystem>
</operatingsystems>

View File

@@ -11,7 +11,6 @@
<package_format>rpm</package_format>
<package_management>yum</package_management>
<hostname>rhel6x32.home.annexia.org</hostname>
<format>installed</format>
<mountpoints>
<mountpoint dev="/dev/vg_rhel6x32/lv_root">/</mountpoint>
<mountpoint dev="/dev/sda1">/boot</mountpoint>

View File

@@ -1,23 +0,0 @@
<?xml version="1.0"?>
<operatingsystems>
<operatingsystem>
<root>/dev/sda</root>
<name>linux</name>
<distro>ubuntu</distro>
<product_name>Ubuntu 10.10 &quot;Maverick Meerkat&quot; - Release amd64 (20101007)</product_name>
<major_version>10</major_version>
<minor_version>10</minor_version>
<format>installer</format>
<live/>
<mountpoints>
<mountpoint dev="/dev/sda">/</mountpoint>
</mountpoints>
<filesystems>
<filesystem dev="/dev/sda">
<type>iso9660</type>
<label>Ubuntu 10.10 amd64</label>
</filesystem>
</filesystems>
<applications/>
</operatingsystem>
</operatingsystems>

View File

@@ -11,7 +11,6 @@
<package_format>deb</package_format>
<package_management>apt</package_management>
<hostname>ubuntu1304.home.annexia.org</hostname>
<format>installed</format>
<mountpoints>
<mountpoint dev="/dev/sda1">/</mountpoint>
</mountpoints>

View File

@@ -1,24 +0,0 @@
<?xml version="1.0"?>
<operatingsystems>
<operatingsystem>
<root>/dev/sda</root>
<name>windows</name>
<arch>x86_64</arch>
<distro>windows</distro>
<product_name>Windows Server 2003 Enterprise x64 Edition</product_name>
<major_version>5</major_version>
<minor_version>2</minor_version>
<windows_systemroot>\WINDOWS</windows_systemroot>
<format>installer</format>
<mountpoints>
<mountpoint dev="/dev/sda">/</mountpoint>
</mountpoints>
<filesystems>
<filesystem dev="/dev/sda">
<type>iso9660</type>
<label>CRMEXFPP_EN</label>
</filesystem>
</filesystems>
<applications/>
</operatingsystem>
</operatingsystems>

View File

@@ -1,24 +0,0 @@
<?xml version="1.0"?>
<operatingsystems>
<operatingsystem>
<root>/dev/sda</root>
<name>windows</name>
<arch>i386</arch>
<distro>windows</distro>
<product_name>Windows Server 2003, Enterprise</product_name>
<major_version>5</major_version>
<minor_version>2</minor_version>
<windows_systemroot>\WINDOWS</windows_systemroot>
<format>installer</format>
<mountpoints>
<mountpoint dev="/dev/sda">/</mountpoint>
</mountpoints>
<filesystems>
<filesystem dev="/dev/sda">
<type>iso9660</type>
<label>CRMEFPP_EN</label>
</filesystem>
</filesystems>
<applications/>
</operatingsystem>
</operatingsystems>

View File

@@ -1,24 +0,0 @@
<?xml version="1.0"?>
<operatingsystems>
<operatingsystem>
<root>/dev/sda</root>
<name>windows</name>
<arch>i386</arch>
<distro>windows</distro>
<product_name>Windows XP Professional</product_name>
<major_version>5</major_version>
<minor_version>1</minor_version>
<windows_systemroot>\WINDOWS</windows_systemroot>
<format>installer</format>
<mountpoints>
<mountpoint dev="/dev/sda">/</mountpoint>
</mountpoints>
<filesystems>
<filesystem dev="/dev/sda">
<type>iso9660</type>
<label>GRTMPFPP_EN</label>
</filesystem>
</filesystems>
<applications/>
</operatingsystem>
</operatingsystems>

View File

@@ -12,7 +12,6 @@
<windows_systemroot>/Windows</windows_systemroot>
<windows_current_control_set>ControlSet001</windows_current_control_set>
<hostname>WIN-6AOV5N85H2F</hostname>
<format>installed</format>
<mountpoints>
<mountpoint dev="/dev/sda2">/</mountpoint>
</mountpoints>

View File

@@ -10,7 +10,6 @@
<package_format>pacman</package_format>
<package_management>pacman</package_management>
<hostname>archlinux.test</hostname>
<format>installed</format>
<mountpoints>
<mountpoint dev="/dev/sda1">/</mountpoint>
</mountpoints>

View File

@@ -8,7 +8,6 @@
<major_version>899</major_version>
<minor_version>13</minor_version>
<hostname>coreos.invalid</hostname>
<format>installed</format>
<mountpoints>
<mountpoint dev="/dev/sda5">/</mountpoint>
<mountpoint dev="/dev/sda3">/usr</mountpoint>

View File

@@ -11,7 +11,6 @@
<package_format>deb</package_format>
<package_management>apt</package_management>
<hostname>debian.invalid</hostname>
<format>installed</format>
<mountpoints>
<mountpoint dev="/dev/debian/root">/</mountpoint>
<mountpoint dev="/dev/debian/usr">/usr</mountpoint>

View File

@@ -11,7 +11,6 @@
<package_format>rpm</package_format>
<package_management>yum</package_management>
<hostname>fedora.invalid</hostname>
<format>installed</format>
<mountpoints>
<mountpoint dev="/dev/VG/Root">/</mountpoint>
<mountpoint dev="/dev/sda1">/boot</mountpoint>

View File

@@ -11,7 +11,6 @@
<package_format>deb</package_format>
<package_management>apt</package_management>
<hostname>ubuntu.invalid</hostname>
<format>installed</format>
<mountpoints>
<mountpoint dev="/dev/sda2">/</mountpoint>
<mountpoint dev="/dev/sda1">/boot</mountpoint>

View File

@@ -12,7 +12,6 @@
<windows_systemroot>/Windows</windows_systemroot>
<windows_current_control_set>ControlSet001</windows_current_control_set>
<hostname>windows.invalid</hostname>
<format>installed</format>
<mountpoints>
<mountpoint dev="/dev/sda2">/</mountpoint>
</mountpoints>

View File

@@ -343,7 +343,7 @@ static void
output_root (xmlTextWriterPtr xo, char *root)
{
char *str;
int i, r;
int i;
char buf[32];
char *canonical_root;
size_t size;
@@ -443,35 +443,6 @@ output_root (xmlTextWriterPtr xo, char *root)
BAD_CAST str));
free (str);
str = guestfs_inspect_get_format (g, root);
if (!str) exit (EXIT_FAILURE);
if (STRNEQ (str, "unknown"))
XMLERROR (-1,
xmlTextWriterWriteElement (xo, BAD_CAST "format",
BAD_CAST str));
free (str);
r = guestfs_inspect_is_live (g, root);
if (r > 0) {
XMLERROR (-1,
xmlTextWriterStartElement (xo, BAD_CAST "live"));
XMLERROR (-1, xmlTextWriterEndElement (xo));
}
r = guestfs_inspect_is_netinst (g, root);
if (r > 0) {
XMLERROR (-1,
xmlTextWriterStartElement (xo, BAD_CAST "netinst"));
XMLERROR (-1, xmlTextWriterEndElement (xo));
}
r = guestfs_inspect_is_multipart (g, root);
if (r > 0) {
XMLERROR (-1,
xmlTextWriterStartElement (xo, BAD_CAST "multipart"));
XMLERROR (-1, xmlTextWriterEndElement (xo));
}
output_mountpoints (xo, root);
output_filesystems (xo, root);

View File

@@ -202,7 +202,6 @@ describe the operating system, its architecture, the descriptive
<major_version>6</major_version>
<minor_version>1</minor_version>
<windows_systemroot>/Windows</windows_systemroot>
<format>installed</format>
In brief, E<lt>nameE<gt> is the class of operating system (something
like C<linux> or C<windows>), E<lt>distroE<gt> is the distribution
@@ -330,27 +329,6 @@ the conversion back to a PNG file:
base64 -i -d < icon.data > icon.png
=head2 INSPECTING INSTALL DISKS, LIVE CDs
Virt-inspector can detect some operating system installers on
install disks, live CDs, bootable USB keys and more.
In this case the E<lt>formatE<gt> tag will contain C<installer>
and other fields may be present to indicate a live CD, network
installer, or one part of a multipart CD. For example:
<operatingsystems>
<operatingsystem>
<root>/dev/sda</root>
<name>linux</name>
<arch>i386</arch>
<distro>ubuntu</distro>
<product_name>Ubuntu 10.10 &quot;Maverick Meerkat&quot;</product_name>
<major_version>10</major_version>
<minor_version>10</minor_version>
<format>installer</format>
<live/>
=head1 XPATH QUERIES
Virt-inspector includes built in support for running XPath queries.

View File

@@ -38,10 +38,6 @@
<optional><ref name="ospackageformat"/></optional>
<optional><ref name="ospackagemanagement"/></optional>
<optional><element name="hostname"><text/></element></optional>
<optional><ref name="osformat"/></optional>
<optional><element name="live"><empty/></element></optional>
<optional><element name="netinst"><empty/></element></optional>
<optional><element name="multipart"><empty/></element></optional>
<ref name="mountpoints"/>
<ref name="filesystems"/>
@@ -152,17 +148,6 @@
</element>
</define>
<!-- the operating system format -->
<define name="osformat">
<element name="format">
<choice>
<value>installed</value>
<value>installer</value>
<!-- "unknown" is intentionally left out -->
</choice>
</element>
</define>
<!-- how filesystems are mounted on mount points -->
<define name="mountpoints">
<element name="mountpoints">

View File

@@ -97,7 +97,6 @@ libguestfs_la_SOURCES = \
inspect.c \
inspect-apps.c \
inspect-fs.c \
inspect-fs-cd.c \
inspect-fs-unix.c \
inspect-fs-windows.c \
inspect-icon.c \
@@ -112,7 +111,6 @@ libguestfs_la_SOURCES = \
lpj.c \
match.c \
mountable.c \
osinfo.c \
private-data.c \
proto.c \
qemu.c \
@@ -134,7 +132,6 @@ libguestfs_la_SOURCES = \
libguestfs_la_CPPFLAGS = \
-DGUESTFS_WARN_DEPRECATED=1 \
-DGUESTFS_PRIVATE=1 \
-DLIBOSINFO_DB_PATH='"$(datadir)/libosinfo/db"' \
-I$(top_srcdir)/common/errnostring -I$(top_builddir)/common/errnostring \
-I$(top_srcdir)/common/protocol -I$(top_builddir)/common/protocol \
-I$(top_srcdir)/common/qemuopts -I$(top_builddir)/common/qemuopts \

View File

@@ -889,10 +889,6 @@ extern char *guestfs_int_case_sensitive_path_silently (guestfs_h *g, const char
extern char * guestfs_int_get_windows_systemroot (guestfs_h *g);
extern int guestfs_int_check_windows_root (guestfs_h *g, struct inspect_fs *fs, char *windows_systemroot);
/* inspect-fs-cd.c */
extern int guestfs_int_check_installer_root (guestfs_h *g, struct inspect_fs *fs);
extern int guestfs_int_check_installer_iso (guestfs_h *g, struct inspect_fs *fs, const char *device);
/* dbdump.c */
typedef int (*guestfs_int_db_dump_callback) (guestfs_h *g, const unsigned char *key, size_t keylen, const unsigned char *value, size_t valuelen, void *opaque);
extern int guestfs_int_read_db_dump (guestfs_h *g, const char *dumpfile, void *opaque, guestfs_int_db_dump_callback callback);
@@ -910,33 +906,6 @@ extern void guestfs_int_free_fuse (guestfs_h *g);
extern virConnectPtr guestfs_int_open_libvirt_connection (guestfs_h *g, const char *uri, unsigned int flags);
#endif
/* osinfo.c */
struct osinfo {
/* Data provided by libosinfo database. */
enum inspect_os_type type;
enum inspect_os_distro distro;
char *product_name;
int major_version;
int minor_version;
char *arch;
int is_live_disk;
bool is_installer;
#if 0
/* Not yet available in libosinfo database. */
char *product_variant;
int is_netinst_disk;
int is_multipart_disk;
#endif
/* The regular expressions used to match ISOs. */
pcre *re_system_id;
pcre *re_volume_id;
pcre *re_publisher_id;
pcre *re_application_id;
};
extern int guestfs_int_osinfo_map (guestfs_h *g, const struct guestfs_isoinfo *isoinfo, const struct osinfo **osinfo_ret);
/* command.c */
struct command;
typedef void (*cmd_stdout_callback) (guestfs_h *g, void *data, const char *line, size_t len);

View File

@@ -939,20 +939,11 @@ documentation for that function for details).
Libguestfs (since 1.9.4) can detect some install disks, install
CDs, live CDs and more.
Call L</guestfs_inspect_get_format> to return the format of the
operating system, which currently can be C<installed> (a regular
operating system) or C<installer> (some sort of install disk).
Further information is available about the operating system that can
be installed using the regular inspection APIs like
L</guestfs_inspect_get_product_name>,
L</guestfs_inspect_get_major_version> etc.
Some additional information specific to installer disks is also
available from the L</guestfs_inspect_is_live>,
L</guestfs_inspect_is_netinst> and L</guestfs_inspect_is_multipart>
calls.
=head2 SPECIAL CONSIDERATIONS FOR WINDOWS GUESTS
Libguestfs can mount NTFS partitions. It does this using the

View File

@@ -1,607 +0,0 @@
/* libguestfs
* Copyright (C) 2010-2012 Red Hat Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libintl.h>
#include <inttypes.h>
#ifdef HAVE_ENDIAN_H
#include <endian.h>
#endif
#include "c-ctype.h"
#include "guestfs.h"
#include "guestfs-internal.h"
#include "structs-cleanups.h"
/* Debian/Ubuntu install disks are easy ...
*
* These files are added by the debian-cd program, and it is worth
* looking at the source code to determine exact values, in
* particular '/usr/share/debian-cd/tools/start_new_disc'
*
* XXX Architecture? We could parse it out of the product name
* string, but that seems quite hairy. We could look for the names
* of packages. Also note that some Debian install disks are
* multiarch.
*/
static int
check_debian_installer_root (guestfs_h *g, struct inspect_fs *fs)
{
fs->product_name = guestfs_int_first_line_of_file (g, "/.disk/info");
if (!fs->product_name)
return -1;
fs->type = OS_TYPE_LINUX;
if (STRPREFIX (fs->product_name, "Ubuntu"))
fs->distro = OS_DISTRO_UBUNTU;
else if (STRPREFIX (fs->product_name, "Debian"))
fs->distro = OS_DISTRO_DEBIAN;
(void) guestfs_int_parse_major_minor (g, fs);
if (guestfs_is_file (g, "/.disk/cd_type") > 0) {
CLEANUP_FREE char *cd_type =
guestfs_int_first_line_of_file (g, "/.disk/cd_type");
if (!cd_type)
return -1;
if (STRPREFIX (cd_type, "dvd/single") ||
STRPREFIX (cd_type, "full_cd/single")) {
fs->is_multipart_disk = 0;
fs->is_netinst_disk = 0;
}
else if (STRPREFIX (cd_type, "dvd") ||
STRPREFIX (cd_type, "full_cd")) {
fs->is_multipart_disk = 1;
fs->is_netinst_disk = 0;
}
else if (STRPREFIX (cd_type, "not_complete")) {
fs->is_multipart_disk = 0;
fs->is_netinst_disk = 1;
}
}
return 0;
}
/* Take string which must look like "key = value" and find the value.
* There may or may not be spaces before and after the equals sign.
* This function is used by both check_fedora_installer_root and
* check_w2k3_installer_root.
*/
static const char *
find_value (const char *kv)
{
const char *p;
p = strchr (kv, '=');
if (!p)
abort ();
do {
++p;
} while (c_isspace (*p));
return p;
}
/* RHEL 5 has a DVD.iso and several CD-sized -discX-ftp.iso alternatives.
*
* The DVD.iso contains:
* /.treeinfo:
* [general]
* family = Red Hat Enterprise Linux Server
* timestamp = 1328200566.61
* totaldiscs = 1
* version = 5.8
* discnum = 1
* packagedir = Server
* arch = x86_64
* [...]
*
* /.discinfo:
* 1328205744.315196
* Red Hat Enterprise Linux Server 5.8 # product name
* x86_64 # arch
* 1 # disk number
* Server/base
* Server/RPMS
* Server/pixmaps
*
* The alternative CD-sized ISOs contain:
*
* disc1:
* /.treeinfo:
* [general]
* family = Red Hat Enterprise Linux Server
* timestamp = 1328200566.61
* totaldiscs = 1
* version = 5.8
* discnum = 1
* packagedir = Server
* arch = x86_64
* [...]
*
* /.discinfo:
* 1328205744.315196
* Red Hat Enterprise Linux Server 5.8 # product name
* x86_64 # arch
* 1 # disk number
* Server/base
* Server/RPMS
* Server/pixmaps
*
* discN (N > 1):
* /.discinfo:
* 1328205744.315196
* Red Hat Enterprise Linux Server 5.8 # product name
* x86_64 # arch
* 2 # disk number
* Server/base
* Server/RPMS
* Server/pixmaps
*/
/* Fedora CDs and DVD (not netinst). The /.treeinfo file contains
* an initial section somewhat like this:
*
* [general]
* version = 14
* arch = x86_64
* family = Fedora
* variant = Fedora
* discnum = 1
* totaldiscs = 1
*/
static int
check_fedora_installer_root (guestfs_h *g, struct inspect_fs *fs)
{
char *str;
const char *v;
int r;
int discnum = 0, totaldiscs = 0;
fs->type = OS_TYPE_LINUX;
r = guestfs_int_first_egrep_of_file (g, "/.treeinfo",
"^family = Fedora$", 0, &str);
if (r == -1)
return -1;
if (r > 0) {
fs->distro = OS_DISTRO_FEDORA;
free (str);
}
r = guestfs_int_first_egrep_of_file (g, "/.treeinfo",
"^family = Red Hat Enterprise Linux$",
0, &str);
if (r == -1)
return -1;
if (r > 0) {
fs->distro = OS_DISTRO_RHEL;
free (str);
}
r = guestfs_int_first_egrep_of_file (g, "/.treeinfo",
"^family = Oracle Linux Server$",
0, &str);
if (r == -1)
return -1;
if (r > 0) {
fs->distro = OS_DISTRO_ORACLE_LINUX;
free (str);
}
/* XXX should do major.minor before this */
r = guestfs_int_first_egrep_of_file (g, "/.treeinfo",
"^version = [[:digit:]]+", 0, &str);
if (r == -1)
return -1;
if (r > 0) {
v = find_value (str);
fs->version.v_major = guestfs_int_parse_unsigned_int_ignore_trailing (g, v);
free (str);
if (fs->version.v_major == -1)
return -1;
}
r = guestfs_int_first_egrep_of_file (g, "/.treeinfo",
"^arch = [-_[:alnum:]]+$", 0, &str);
if (r == -1)
return -1;
if (r > 0) {
v = find_value (str);
fs->arch = safe_strdup (g, v);
free (str);
}
r = guestfs_int_first_egrep_of_file (g, "/.treeinfo",
"^discnum = [[:digit:]]+$", 0, &str);
if (r == -1)
return -1;
if (r > 0) {
v = find_value (str);
discnum = guestfs_int_parse_unsigned_int (g, v);
free (str);
if (discnum == -1)
return -1;
}
r = guestfs_int_first_egrep_of_file (g, "/.treeinfo",
"^totaldiscs = [[:digit:]]+$", 0, &str);
if (r == -1)
return -1;
if (r > 0) {
v = find_value (str);
totaldiscs = guestfs_int_parse_unsigned_int (g, v);
free (str);
if (totaldiscs == -1)
return -1;
}
fs->is_multipart_disk = totaldiscs > 1;
/* and what about discnum? */
return 0;
}
/* Linux with /isolinux/isolinux.cfg.
*
* This file is not easily parsable so we have to do our best.
* Look for the "menu title" line which contains:
* menu title Welcome to Fedora 14! # since at least Fedora 10
* menu title Welcome to Red Hat Enterprise Linux 6.0!
* menu title Welcome to RHEL6.2-20111117.0-Workstation-x!
*/
static int
check_isolinux_installer_root (guestfs_h *g, struct inspect_fs *fs)
{
char *str;
int r;
fs->type = OS_TYPE_LINUX;
r = guestfs_int_first_egrep_of_file (g, "/isolinux/isolinux.cfg",
"^menu title Welcome to Fedora [[:digit:]]+",
0, &str);
if (r == -1)
return -1;
if (r > 0) {
fs->distro = OS_DISTRO_FEDORA;
fs->version.v_major =
guestfs_int_parse_unsigned_int_ignore_trailing (g, &str[29]);
free (str);
if (fs->version.v_major == -1)
return -1;
}
/* XXX parse major.minor */
r = guestfs_int_first_egrep_of_file (g, "/isolinux/isolinux.cfg",
"^menu title Welcome to Red Hat Enterprise Linux [[:digit:]]+",
0, &str);
if (r == -1)
return -1;
if (r > 0) {
fs->distro = OS_DISTRO_RHEL;
fs->version.v_major =
guestfs_int_parse_unsigned_int_ignore_trailing (g, &str[47]);
free (str);
if (fs->version.v_major == -1)
return -1;
}
/* XXX parse major.minor */
r = guestfs_int_first_egrep_of_file (g, "/isolinux/isolinux.cfg",
"^menu title Welcome to RHEL[[:digit:]]+",
0, &str);
if (r == -1)
return -1;
if (r > 0) {
fs->distro = OS_DISTRO_RHEL;
fs->version.v_major =
guestfs_int_parse_unsigned_int_ignore_trailing (g, &str[26]);
free (str);
if (fs->version.v_major == -1)
return -1;
}
/* XXX parse major.minor */
r = guestfs_int_first_egrep_of_file (g, "/isolinux/isolinux.cfg",
"^menu title Welcome to Oracle Linux Server [[:digit:]]+",
0, &str);
if (r == -1)
return -1;
if (r > 0) {
fs->distro = OS_DISTRO_ORACLE_LINUX;
fs->version.v_major =
guestfs_int_parse_unsigned_int_ignore_trailing (g, &str[42]);
free (str);
if (fs->version.v_major == -1)
return -1;
}
return 0;
}
/* Windows 2003 and similar versions.
*
* NB: txtsetup file contains Windows \r\n line endings, which guestfs_grep
* does not remove. We have to remove them by hand here.
*/
static void
trim_cr (char *str)
{
const size_t n = strlen (str);
if (n > 0 && str[n-1] == '\r')
str[n-1] = '\0';
}
static void
trim_quot (char *str)
{
const size_t n = strlen (str);
if (n > 0 && str[n-1] == '"')
str[n-1] = '\0';
}
static int
check_w2k3_installer_root (guestfs_h *g, struct inspect_fs *fs,
const char *txtsetup)
{
char *str;
const char *v;
int r;
fs->type = OS_TYPE_WINDOWS;
fs->distro = OS_DISTRO_WINDOWS;
r = guestfs_int_first_egrep_of_file (g, txtsetup,
"^productname[[:space:]]*=[[:space:]]*\"", 1, &str);
if (r == -1)
return -1;
if (r > 0) {
trim_cr (str);
trim_quot (str);
v = find_value (str);
fs->product_name = safe_strdup (g, v+1);
free (str);
}
r = guestfs_int_first_egrep_of_file (g, txtsetup,
"^majorversion[[:space:]]*=[[:space:]]*[[:digit:]]+",
1, &str);
if (r == -1)
return -1;
if (r > 0) {
trim_cr (str);
v = find_value (str);
fs->version.v_major = guestfs_int_parse_unsigned_int_ignore_trailing (g, v);
free (str);
if (fs->version.v_major == -1)
return -1;
}
r = guestfs_int_first_egrep_of_file (g, txtsetup,
"^minorversion[[:space:]]*=[[:space:]]*[[:digit:]]+",
1, &str);
if (r == -1)
return -1;
if (r > 0) {
trim_cr (str);
v = find_value (str);
fs->version.v_minor = guestfs_int_parse_unsigned_int_ignore_trailing (g, v);
free (str);
if (fs->version.v_minor == -1)
return -1;
}
/* This is the windows systemroot that would be chosen on
* installation by default, although not necessarily the one that
* the user will finally choose.
*/
r = guestfs_int_first_egrep_of_file (g, txtsetup,
"^defaultpath[[:space:]]*=[[:space:]]*",
1, &str);
if (r == -1)
return -1;
if (r > 0) {
trim_cr (str);
v = find_value (str);
fs->windows_systemroot = safe_strdup (g, v);
free (str);
}
return 0;
}
/* Read the data from a product.id-like file.
*
* This is an old file, mostly used in Mandriva-based systems (still including
* Mageia). A very minimal documentation for it is:
* - https://wiki.mageia.org/en/Product_id
* - http://wiki.mandriva.com/en/Product_id (old URL, defunct)
*/
static int
check_product_id_installer_root (guestfs_h *g, struct inspect_fs *fs,
const char *filename)
{
CLEANUP_FREE char *line = NULL;
const char *elem;
char *saveptr;
fs->type = OS_TYPE_LINUX;
line = guestfs_int_first_line_of_file (g, filename);
if (line == NULL)
return -1;
elem = strtok_r (line, ",", &saveptr);
while (elem) {
const char *equal = strchr (elem, '=');
if (equal == NULL || equal == elem)
return -1;
const char *value = equal + 1;
if (STRPREFIX (elem, "distribution=")) {
if (STREQ (value, "Mageia"))
fs->distro = OS_DISTRO_MAGEIA;
} else if (STRPREFIX (elem, "version=")) {
if (guestfs_int_version_from_x_y_or_x (g, &fs->version, value) == -1)
return -1;
} else if (STRPREFIX (elem, "arch=")) {
fs->arch = safe_strdup (g, value);
}
elem = strtok_r (NULL, ",", &saveptr);
}
/* Not found. */
return 0;
}
/* The currently mounted device is very likely to be an installer. */
int
guestfs_int_check_installer_root (guestfs_h *g, struct inspect_fs *fs)
{
CLEANUP_FREE_STRING_LIST char **paths = NULL;
/* The presence of certain files indicates a live CD.
*
* XXX Fedora netinst contains a ~120MB squashfs called
* /images/install.img. However this is not a live CD (unlike the
* Fedora live CDs which contain the same, but larger file). We
* need to unpack this and look inside to tell the difference.
*/
if (guestfs_is_file (g, "/casper/filesystem.squashfs") > 0 ||
guestfs_is_file (g, "/live/filesystem.squashfs") > 0 ||
guestfs_is_file (g, "/mfsroot.gz") > 0)
fs->is_live_disk = 1;
/* Debian/Ubuntu. */
if (guestfs_is_file (g, "/.disk/info") > 0) {
if (check_debian_installer_root (g, fs) == -1)
return -1;
}
/* Fedora CDs and DVD (not netinst). */
else if (guestfs_is_file (g, "/.treeinfo") > 0) {
if (check_fedora_installer_root (g, fs) == -1)
return -1;
}
/* FreeDOS install CD. */
else if (guestfs_is_file (g, "/freedos/freedos.ico") > 0 &&
guestfs_is_file (g, "/setup.bat") > 0) {
fs->type = OS_TYPE_DOS;
fs->distro = OS_DISTRO_FREEDOS;
fs->arch = safe_strdup (g, "i386");
}
/* Linux with /isolinux/isolinux.cfg (note that non-Linux can use
* ISOLINUX too, eg. FreeDOS).
*/
else if (guestfs_is_file (g, "/isolinux/isolinux.cfg") > 0) {
if (check_isolinux_installer_root (g, fs) == -1)
return -1;
}
/* FreeBSD with /boot/loader.rc. */
else if (guestfs_is_file (g, "/boot/loader.rc") > 0) {
fs->type = OS_TYPE_FREEBSD;
}
/* Windows 2003 64 bit */
else if (guestfs_is_file (g, "/amd64/txtsetup.sif") > 0) {
fs->arch = safe_strdup (g, "x86_64");
if (check_w2k3_installer_root (g, fs, "/amd64/txtsetup.sif") == -1)
return -1;
}
/* Windows 2003 32 bit */
else if (guestfs_is_file (g, "/i386/txtsetup.sif") > 0) {
fs->arch = safe_strdup (g, "i386");
if (check_w2k3_installer_root (g, fs, "/i386/txtsetup.sif") == -1)
return -1;
}
/* Linux with /{i586,x86_64,etc}/product.id (typically found in Mandriva
* and Mageia). Usually there should be just one around, so we use the
* first one found.
*/
paths = guestfs_glob_expand (g, "/*/product.id");
if (paths == NULL)
return -1;
if (paths[0] != NULL) {
if (check_product_id_installer_root (g, fs, paths[0]) == -1)
return -1;
}
return 0;
}
/* This is called for whole block devices. See if the device is an
* ISO and we are able to read the ISO info from it. In that case,
* try using libosinfo to map from the volume ID and other strings
* directly to the operating system type.
*/
int
guestfs_int_check_installer_iso (guestfs_h *g, struct inspect_fs *fs,
const char *device)
{
CLEANUP_FREE_ISOINFO struct guestfs_isoinfo *isoinfo = NULL;
const struct osinfo *osinfo;
int r;
guestfs_push_error_handler (g, NULL, NULL);
isoinfo = guestfs_isoinfo_device (g, device);
guestfs_pop_error_handler (g);
if (!isoinfo)
return 0;
r = guestfs_int_osinfo_map (g, isoinfo, &osinfo);
if (r == -1) /* Fatal error. */
return -1;
if (r == 0) /* Could not locate any matching ISO. */
return 0;
/* Otherwise we matched an ISO, so fill in the fs fields. */
fs->mountable = safe_strdup (g, device);
fs->role = OS_ROLE_ROOT;
if (osinfo->is_installer)
fs->format = OS_FORMAT_INSTALLER;
fs->type = osinfo->type;
fs->distro = osinfo->distro;
fs->product_name =
osinfo->product_name ? safe_strdup (g, osinfo->product_name) : NULL;
guestfs_int_version_from_values (&fs->version, osinfo->major_version,
osinfo->minor_version, 0);
fs->arch = osinfo->arch ? safe_strdup (g, osinfo->arch) : NULL;
fs->is_live_disk = osinfo->is_live_disk;
guestfs_int_check_package_format (g, fs);
guestfs_int_check_package_management (g, fs);
return 1;
}

View File

@@ -87,22 +87,6 @@ guestfs_int_check_for_filesystem_on (guestfs_h *g, const char *mountable)
}
}
if (whole_device) {
extend_fses (g);
fs = &g->fses[g->nr_fses-1];
r = guestfs_int_check_installer_iso (g, fs, m->im_device);
if (r == -1) { /* Fatal error. */
g->nr_fses--;
return -1;
}
if (r > 0) /* Found something. */
return 0;
/* Didn't find anything. Fall through ... */
g->nr_fses--;
}
/* Try mounting the device. As above, ignore errors. */
guestfs_push_error_handler (g, NULL, NULL);
if (vfs_type && STREQ (vfs_type, "ufs")) { /* Hack for the *BSDs. */
@@ -290,30 +274,6 @@ check_filesystem (guestfs_h *g, const char *mountable,
*/
fs->arch = safe_strdup (g, "i386");
}
/* Install CD/disk?
*
* Note that we checked (above) for an install ISO, but there are
* other types of install image (eg. USB keys) which that check
* wouldn't have picked up.
*
* Skip these checks if it's not a whole device (eg. CD) or the
* first partition (eg. bootable USB key).
*/
else if ((whole_device || (partnum == 1 && nr_partitions == 1)) &&
(guestfs_is_file (g, "/isolinux/isolinux.cfg") > 0 ||
guestfs_is_dir (g, "/EFI/BOOT") > 0 ||
guestfs_is_file (g, "/images/install.img") > 0 ||
guestfs_is_dir (g, "/.disk") > 0 ||
guestfs_is_file (g, "/.discinfo") > 0 ||
guestfs_is_file (g, "/i386/txtsetup.sif") > 0 ||
guestfs_is_file (g, "/amd64/txtsetup.sif") > 0 ||
guestfs_is_file (g, "/freedos/freedos.ico") > 0 ||
guestfs_is_file (g, "/boot/loader.rc") > 0)) {
fs->role = OS_ROLE_ROOT;
fs->format = OS_FORMAT_INSTALLER;
if (guestfs_int_check_installer_root (g, fs) == -1)
return -1;
}
/* The above code should have set fs->type and fs->distro fields, so
* we can now guess the package management system.

View File

@@ -1,655 +0,0 @@
/* libguestfs
* Copyright (C) 2012 Red Hat Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/* Read libosinfo XML files to parse out just the
* os/media/iso/system-id and os/media/iso/volume-id fields, which we
* can then use to map install media to operating systems.
*
* Note some assumptions here:
*
* (1) Ignore the libosinfo library itself, since we don't care
* for GObject nonsense. The XML database contains all we need.
*
* (2) Ignore os/upgrades and os/derives-from fields. This is
* safe(-ish) since the media identifiers always change for every
* release of an OS. We can easily add support for this if it becomes
* necessary.
*
* (3) We have to do some translation of the distro names and versions
* stored in the libosinfo files and the standard names returned by
* libguestfs.
*
* (4) Media detection is only part of the story. We may still need
* to inspect inside the image.
*
* (5) We only read the XML database files (at most) once per process,
* and keep them cached. They are only read at all if someone tries
* to inspect a CD/DVD/ISO.
*
* XXX Currently the database is not freed when the program exits /
* library is unloaded, although we should probably do that.
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <dirent.h>
#include <assert.h>
#include <sys/types.h>
#include <libintl.h>
#include <sys/stat.h>
#include <libxml/parser.h>
#include <libxml/xpath.h>
#include "ignore-value.h"
#include "glthread/lock.h"
#include "c-ctype.h"
#include "guestfs.h"
#include "guestfs-internal.h"
gl_lock_define_initialized (static, osinfo_db_lock);
static ssize_t osinfo_db_size = 0; /* 0 = unread, -1 = error, >= 1 = #records */
static struct osinfo *osinfo_db = NULL;
static int read_osinfo_db (guestfs_h *g);
static void free_osinfo_db_entry (struct osinfo *);
#define XMLSTREQ(a,b) (xmlStrEqual((a),(b)) == 1)
/* Given one or more fields from the header of a CD/DVD/ISO, look up
* the media in the libosinfo database and return our best guess for
* the operating system.
*
* This returns:
* -1 => a fatal error ('error' has been called, caller must not ignore it)
* 0 => could not locate the OS
* 1 => matching OS found, the osinfo_ret pointer has been filled in
*/
int
guestfs_int_osinfo_map (guestfs_h *g, const struct guestfs_isoinfo *isoinfo,
const struct osinfo **osinfo_ret)
{
size_t i;
/* We only need to lock the database when reading it for the first time. */
gl_lock_lock (osinfo_db_lock);
if (osinfo_db_size == 0) {
if (read_osinfo_db (g) == -1) {
gl_lock_unlock (osinfo_db_lock);
return -1;
}
}
gl_lock_unlock (osinfo_db_lock);
if (osinfo_db_size <= 0)
return 0;
/* Look in the database to see if we can find a match. */
for (i = 0; i < (size_t) osinfo_db_size; ++i) {
if (osinfo_db[i].re_system_id) {
if (!isoinfo->iso_system_id ||
!match (g, isoinfo->iso_system_id, osinfo_db[i].re_system_id))
continue;
}
if (osinfo_db[i].re_volume_id) {
if (!isoinfo->iso_volume_id ||
!match (g, isoinfo->iso_volume_id, osinfo_db[i].re_volume_id))
continue;
}
if (osinfo_db[i].re_publisher_id) {
if (!isoinfo->iso_publisher_id ||
!match (g, isoinfo->iso_publisher_id, osinfo_db[i].re_publisher_id))
continue;
}
if (osinfo_db[i].re_application_id) {
if (!isoinfo->iso_application_id ||
!match (g, isoinfo->iso_application_id, osinfo_db[i].re_application_id))
continue;
}
debug (g, "osinfo: mapped disk to database entry %zu", i);
if (osinfo_ret)
*osinfo_ret = &osinfo_db[i];
return 1;
}
debug (g, "osinfo: no mapping found");
return 0;
}
/* Read the libosinfo XML database files. The lock is held while
* this is called.
*
* Returns:
* -1 => a fatal error ('error' has been called)
* 0 => OK
*
* Note that failure to find or parse the XML files is *not* a fatal
* error, since we should fall back silently if these are not
* available. Although we'll emit some debug if this happens.
*
* Try to use the shared osinfo database layout (and location) first:
* https://gitlab.com/libosinfo/libosinfo/blob/master/docs/database-layout.txt
*/
static int read_osinfo_db_xml (guestfs_h *g, const char *filename);
static int read_osinfo_db_flat (guestfs_h *g, const char *directory);
static int read_osinfo_db_three_levels (guestfs_h *g, const char *directory);
static int read_osinfo_db_directory (guestfs_h *g, const char *directory);
static int
read_osinfo_db (guestfs_h *g)
{
int r;
size_t i;
assert (osinfo_db_size == 0);
/* (1) Try the shared osinfo directory, using either the
* $OSINFO_SYSTEM_DIR envvar or its default value.
*/
{
const char *path;
CLEANUP_FREE char *os_path = NULL;
path = getenv ("OSINFO_SYSTEM_DIR");
if (path == NULL)
path = "/usr/share/osinfo";
os_path = safe_asprintf (g, "%s/os", path);
r = read_osinfo_db_three_levels (g, os_path);
}
if (r == -1)
goto error;
else if (r == 1)
return 0;
/* (2) Try the libosinfo directory, using the newer three-directory
* layout ($LIBOSINFO_DB_PATH / "os" / $group-ID / [file.xml]).
*/
r = read_osinfo_db_three_levels (g, LIBOSINFO_DB_PATH "/os");
if (r == -1)
goto error;
else if (r == 1)
return 0;
/* (3) Try the libosinfo directory, using the old flat directory
* layout ($LIBOSINFO_DB_PATH / "oses" / [file.xml]).
*/
r = read_osinfo_db_flat (g, LIBOSINFO_DB_PATH "/oses");
if (r == -1)
goto error;
else if (r == 1)
return 0;
/* Nothing found. */
return 0;
error:
/* Fatal error: free any database entries which have been read, and
* mark the database as having a permanent error.
*/
if (osinfo_db_size > 0) {
for (i = 0; i < (size_t) osinfo_db_size; ++i)
free_osinfo_db_entry (&osinfo_db[i]);
}
free (osinfo_db);
osinfo_db = NULL;
osinfo_db_size = -1;
return -1;
}
static int
read_osinfo_db_flat (guestfs_h *g, const char *directory)
{
debug (g, "osinfo: loading flat database from %s", directory);
return read_osinfo_db_directory (g, directory);
}
static int
read_osinfo_db_three_levels (guestfs_h *g, const char *directory)
{
DIR *dir;
int r;
dir = opendir (directory);
if (!dir) {
debug (g, "osinfo: %s: %s", directory, strerror (errno));
return 0; /* This is not an error: RHBZ#948324. */
}
debug (g, "osinfo: loading 3-level-directories database from %s", directory);
for (;;) {
struct dirent *d;
CLEANUP_FREE char *pathname = NULL;
struct stat sb;
errno = 0;
d = readdir (dir);
if (!d) break;
pathname = safe_asprintf (g, "%s/%s", directory, d->d_name);
/* Iterate only on directories. */
if (stat (pathname, &sb) == 0 && S_ISDIR (sb.st_mode)) {
r = read_osinfo_db_directory (g, pathname);
if (r == -1)
goto error;
}
}
/* Check for failure in readdir. */
if (errno != 0) {
perrorf (g, "readdir: %s", directory);
goto error;
}
/* Close the directory handle. */
r = closedir (dir);
dir = NULL;
if (r == -1) {
perrorf (g, "closedir: %s", directory);
goto error;
}
return 1;
error:
if (dir)
closedir (dir);
return -1;
}
static int
read_osinfo_db_directory (guestfs_h *g, const char *directory)
{
DIR *dir;
int r;
dir = opendir (directory);
if (!dir) {
debug (g, "osinfo: %s: %s", directory, strerror (errno));
return 0; /* This is not an error: RHBZ#948324. */
}
for (;;) {
struct dirent *d;
errno = 0;
d = readdir (dir);
if (!d) break;
if (STRSUFFIX (d->d_name, ".xml")) {
CLEANUP_FREE char *pathname = NULL;
pathname = safe_asprintf (g, "%s/%s", directory, d->d_name);
r = read_osinfo_db_xml (g, pathname);
if (r == -1)
goto error;
}
}
/* Check for failure in readdir. */
if (errno != 0) {
perrorf (g, "readdir: %s", directory);
goto error;
}
/* Close the directory handle. */
r = closedir (dir);
dir = NULL;
if (r == -1) {
perrorf (g, "closedir: %s", directory);
goto error;
}
return 1;
error:
if (dir)
closedir (dir);
return -1;
}
static int read_iso_node (guestfs_h *g, xmlNodePtr iso_node, struct osinfo *osinfo);
static int read_media_node (guestfs_h *g, xmlXPathContextPtr xpathCtx, xmlNodePtr media_node, struct osinfo *osinfo);
static int read_os_node (guestfs_h *g, xmlXPathContextPtr xpathCtx, xmlNodePtr os_node, struct osinfo *osinfo);
/* Read a single XML file from pathname (which is a full path).
* Only memory allocation failures are fatal errors here.
*/
static int
read_osinfo_db_xml (guestfs_h *g, const char *pathname)
{
CLEANUP_XMLFREEDOC xmlDocPtr doc = NULL;
CLEANUP_XMLXPATHFREECONTEXT xmlXPathContextPtr xpathCtx = NULL;
CLEANUP_XMLXPATHFREEOBJECT xmlXPathObjectPtr xpathObj = NULL;
xmlNodeSetPtr nodes;
xmlNodePtr iso_node, media_node, os_node;
struct osinfo *osinfo;
size_t i;
doc = xmlReadFile (pathname, NULL, XML_PARSE_NONET);
if (doc == NULL) {
debug (g, "osinfo: unable to parse XML file %s", pathname);
return 0;
}
xpathCtx = xmlXPathNewContext (doc);
if (xpathCtx == NULL) {
error (g, _("osinfo: unable to create new XPath context"));
return -1;
}
/* Get all <iso> nodes at any depth, then use the parent pointers in
* order to work back up the tree.
*/
xpathObj = xmlXPathEvalExpression (BAD_CAST "/libosinfo/os/media/iso",
xpathCtx);
if (xpathObj == NULL) {
error (g, _("osinfo: %s: unable to evaluate XPath expression"),
pathname);
return -1;
}
nodes = xpathObj->nodesetval;
if (nodes != NULL) {
for (i = 0; i < (size_t) nodes->nodeNr; ++i) {
iso_node = nodes->nodeTab[i];
assert (iso_node != NULL);
assert (STREQ ((const char *) iso_node->name, "iso"));
assert (iso_node->type == XML_ELEMENT_NODE);
media_node = iso_node->parent;
assert (media_node != NULL);
assert (STREQ ((const char *) media_node->name, "media"));
assert (media_node->type == XML_ELEMENT_NODE);
os_node = media_node->parent;
assert (os_node != NULL);
assert (STREQ ((const char *) os_node->name, "os"));
assert (os_node->type == XML_ELEMENT_NODE);
/* Allocate an osinfo record. */
osinfo_db_size++;
osinfo_db = safe_realloc (g, osinfo_db,
sizeof (struct osinfo) * osinfo_db_size);
osinfo = &osinfo_db[osinfo_db_size-1];
memset (osinfo, 0, sizeof *osinfo);
/* Read XML fields into the new osinfo record. */
if (read_iso_node (g, iso_node, osinfo) == -1 ||
read_media_node (g, xpathCtx, media_node, osinfo) == -1 ||
read_os_node (g, xpathCtx, os_node, osinfo) == -1) {
free_osinfo_db_entry (osinfo);
osinfo_db_size--;
return -1;
}
#if 0
debug (g, "osinfo: %s: %s%s%s%s=> arch %s live %s installer %s product %s type %d distro %d version %d.%d",
pathname,
osinfo->re_system_id ? "<system-id/> " : "",
osinfo->re_volume_id ? "<volume-id/> " : "",
osinfo->re_publisher_id ? "<publisher-id/> " : "",
osinfo->re_application_id ? "<application-id/> " : "",
osinfo->arch ? osinfo->arch : "(none)",
osinfo->is_live_disk ? "true" : "false",
osinfo->is_installer ? "true" : "false",
osinfo->product_name ? osinfo->product_name : "(none)",
(int) osinfo->type, (int) osinfo->distro,
osinfo->major_version, osinfo->minor_version);
#endif
}
}
return 0;
}
static int compile_re (guestfs_h *g, xmlNodePtr child, pcre **re);
/* Read the regular expressions under the <iso> node. libosinfo
* itself uses the glib function 'g_regex_match_simple'. That appears
* to implement PCRE, however I have not checked in detail.
*/
static int
read_iso_node (guestfs_h *g, xmlNodePtr iso_node, struct osinfo *osinfo)
{
xmlNodePtr child;
for (child = iso_node->children; child; child = child->next) {
if (STREQ ((const char *) child->name, "system-id")) {
if (compile_re (g, child, &osinfo->re_system_id) == -1)
return -1;
}
else if (STREQ ((const char *) child->name, "volume-id")) {
if (compile_re (g, child, &osinfo->re_volume_id) == -1)
return -1;
}
else if (STREQ ((const char *) child->name, "publisher-id")) {
if (compile_re (g, child, &osinfo->re_publisher_id) == -1)
return -1;
}
else if (STREQ ((const char *) child->name, "application-id")) {
if (compile_re (g, child, &osinfo->re_application_id) == -1)
return -1;
}
}
return 0;
}
static int
compile_re (guestfs_h *g, xmlNodePtr node, pcre **re)
{
const char *err;
int offset;
CLEANUP_FREE char *content = (char *) xmlNodeGetContent (node);
if (content) {
*re = pcre_compile (content, 0, &err, &offset, NULL);
if (*re == NULL)
debug (g, "osinfo: could not parse regular expression '%s': %s (ignored)",
content, err);
}
return 0;
}
/* Read the attributes of the <media/> node. */
static int
read_media_node (guestfs_h *g, xmlXPathContextPtr xpathCtx,
xmlNodePtr media_node, struct osinfo *osinfo)
{
osinfo->arch = (char *) xmlGetProp (media_node, BAD_CAST "arch");
osinfo->is_live_disk = 0; /* If no 'live' attr, defaults to false. */
{
CLEANUP_XMLFREE xmlChar *content = NULL;
content = xmlGetProp (media_node, BAD_CAST "live");
if (content)
osinfo->is_live_disk = XMLSTREQ (content, BAD_CAST "true");
}
osinfo->is_installer = true; /* If no 'installer' attr, defaults to true. */
{
CLEANUP_XMLFREE xmlChar *content = NULL;
content = xmlGetProp (media_node, BAD_CAST "installer");
if (content)
osinfo->is_installer = XMLSTREQ (content, BAD_CAST "true");
}
return 0;
}
static int parse_version (guestfs_h *g, xmlNodePtr node, struct osinfo *osinfo);
static int parse_family (guestfs_h *g, xmlNodePtr node, struct osinfo *osinfo);
static int parse_distro (guestfs_h *g, xmlNodePtr node, struct osinfo *osinfo);
/* Read some fields under the <os/> node. */
static int
read_os_node (guestfs_h *g, xmlXPathContextPtr xpathCtx,
xmlNodePtr os_node, struct osinfo *osinfo)
{
xmlNodePtr child;
for (child = os_node->children; child; child = child->next) {
if (STREQ ((const char *) child->name, "name"))
osinfo->product_name = (char *) xmlNodeGetContent (child);
else if (STREQ ((const char *) child->name, "version")) {
if (parse_version (g, child, osinfo) == -1)
return -1;
}
else if (STREQ ((const char *) child->name, "family")) {
if (parse_family (g, child, osinfo) == -1)
return -1;
}
else if (STREQ ((const char *) child->name, "distro")) {
if (parse_distro (g, child, osinfo) == -1)
return -1;
}
}
return 0;
}
static int
parse_version (guestfs_h *g, xmlNodePtr node, struct osinfo *osinfo)
{
CLEANUP_FREE char *content = NULL;
content = (char *) xmlNodeGetContent (node);
/* We parse either "X.Y" or "X" as version strings, so try to parse
* only if the first character is a digit.
*/
if (content && c_isdigit (content[0])) {
struct version version;
const int res = guestfs_int_version_from_x_y_or_x (g, &version, content);
if (res < 0)
return -1;
else if (res > 0) {
osinfo->major_version = version.v_major;
osinfo->minor_version = version.v_minor;
}
}
return 0;
}
static int
parse_family (guestfs_h *g, xmlNodePtr node, struct osinfo *osinfo)
{
CLEANUP_FREE char *content = NULL;
osinfo->type = OS_TYPE_UNKNOWN;
content = (char *) xmlNodeGetContent (node);
if (content) {
if (STREQ (content, "linux"))
osinfo->type = OS_TYPE_LINUX;
else if (STRPREFIX (content, "win"))
osinfo->type = OS_TYPE_WINDOWS;
else if (STREQ (content, "freebsd"))
osinfo->type = OS_TYPE_FREEBSD;
else if (STREQ (content, "netbsd"))
osinfo->type = OS_TYPE_NETBSD;
else if (STREQ (content, "msdos"))
osinfo->type = OS_TYPE_DOS;
else if (STREQ (content, "openbsd"))
osinfo->type = OS_TYPE_OPENBSD;
else
debug (g, "osinfo: warning: unknown <family> '%s'", content);
}
return 0;
}
static int
parse_distro (guestfs_h *g, xmlNodePtr node, struct osinfo *osinfo)
{
CLEANUP_FREE char *content = NULL;
osinfo->distro = OS_DISTRO_UNKNOWN;
content = (char *) xmlNodeGetContent (node);
if (content) {
if (STREQ (content, "altlinux"))
osinfo->distro = OS_DISTRO_ALTLINUX;
else if (STREQ (content, "centos"))
osinfo->distro = OS_DISTRO_CENTOS;
else if (STREQ (content, "debian"))
osinfo->distro = OS_DISTRO_DEBIAN;
else if (STREQ (content, "fedora"))
osinfo->distro = OS_DISTRO_FEDORA;
else if (STREQ (content, "freebsd"))
osinfo->distro = OS_DISTRO_FREEBSD;
else if (STREQ (content, "mageia"))
osinfo->distro = OS_DISTRO_MAGEIA;
else if (STREQ (content, "mandriva"))
osinfo->distro = OS_DISTRO_MANDRIVA;
else if (STREQ (content, "netbsd"))
osinfo->distro = OS_DISTRO_NETBSD;
else if (STREQ (content, "openbsd"))
osinfo->distro = OS_DISTRO_OPENBSD;
else if (STREQ (content, "opensuse"))
osinfo->distro = OS_DISTRO_OPENSUSE;
else if (STREQ (content, "rhel"))
osinfo->distro = OS_DISTRO_RHEL;
else if (STREQ (content, "sled") || STREQ (content, "sles"))
osinfo->distro = OS_DISTRO_SLES;
else if (STREQ (content, "ubuntu"))
osinfo->distro = OS_DISTRO_UBUNTU;
else if (STRPREFIX (content, "win"))
osinfo->distro = OS_DISTRO_WINDOWS;
else
debug (g, "osinfo: warning: unknown <distro> '%s'", content);
}
return 0;
}
static void
free_osinfo_db_entry (struct osinfo *osinfo)
{
free (osinfo->product_name);
free (osinfo->arch);
if (osinfo->re_system_id)
pcre_free (osinfo->re_system_id);
if (osinfo->re_volume_id)
pcre_free (osinfo->re_volume_id);
if (osinfo->re_publisher_id)
pcre_free (osinfo->re_publisher_id);
if (osinfo->re_application_id)
pcre_free (osinfo->re_application_id);
}