Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

489 lines (434 sloc) 13.084 kb
/* 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 <stdint.h>
#include <inttypes.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <sys/stat.h>
#include <errno.h>
#ifdef HAVE_ENDIAN_H
#include <endian.h>
#endif
#include <pcre.h>
#ifdef HAVE_HIVEX
#include <hivex.h>
#endif
#include "c-ctype.h"
#include "ignore-value.h"
#include "xstrtol.h"
#include "guestfs.h"
#include "guestfs-internal.h"
#include "guestfs-internal-actions.h"
#include "guestfs_protocol.h"
#if defined(HAVE_HIVEX)
/* 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___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___parse_major_minor (g, fs);
if (guestfs_is_file (g, "/.disk/cd_type") > 0) {
char *cd_type = guestfs___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;
}
free (cd_type);
}
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___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___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);
}
/* XXX should do major.minor before this */
r = guestfs___first_egrep_of_file (g, "/.treeinfo",
"^version = [[:digit:]]+", 0, &str);
if (r == -1)
return -1;
if (r > 0) {
v = find_value (str);
fs->major_version = guestfs___parse_unsigned_int_ignore_trailing (g, v);
free (str);
if (fs->major_version == -1)
return -1;
}
r = guestfs___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___first_egrep_of_file (g, "/.treeinfo",
"^discnum = [[:digit:]]+$", 0, &str);
if (r == -1)
return -1;
if (r > 0) {
v = find_value (str);
discnum = guestfs___parse_unsigned_int (g, v);
free (str);
if (discnum == -1)
return -1;
}
r = guestfs___first_egrep_of_file (g, "/.treeinfo",
"^totaldiscs = [[:digit:]]+$", 0, &str);
if (r == -1)
return -1;
if (r > 0) {
v = find_value (str);
totaldiscs = guestfs___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___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->major_version =
guestfs___parse_unsigned_int_ignore_trailing (g, &str[29]);
free (str);
if (fs->major_version == -1)
return -1;
}
/* XXX parse major.minor */
r = guestfs___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->major_version =
guestfs___parse_unsigned_int_ignore_trailing (g, &str[47]);
free (str);
if (fs->major_version == -1)
return -1;
}
/* XXX parse major.minor */
r = guestfs___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->major_version =
guestfs___parse_unsigned_int_ignore_trailing (g, &str[26]);
free (str);
if (fs->major_version == -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)
{
size_t n = strlen (str);
if (n > 0 && str[n-1] == '\r')
str[n-1] = '\0';
}
static void
trim_quot (char *str)
{
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___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___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->major_version = guestfs___parse_unsigned_int_ignore_trailing (g, v);
free (str);
if (fs->major_version == -1)
return -1;
}
r = guestfs___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->minor_version = guestfs___parse_unsigned_int_ignore_trailing (g, v);
free (str);
if (fs->minor_version == -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___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;
}
/* The currently mounted device is very likely to be an installer. */
int
guestfs___check_installer_root (guestfs_h *g, struct inspect_fs *fs)
{
/* 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)
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;
}
/* 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;
}
return 0;
}
#endif /* defined(HAVE_HIVEX) */
Jump to Line
Something went wrong with that request. Please try again.