mirror of
https://github.com/libguestfs/libguestfs.git
synced 2026-03-22 07:03:38 +00:00
656 lines
19 KiB
C
656 lines
19 KiB
C
/* 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);
|
|
}
|