X-Git-Url: http://git.annexia.org/?a=blobdiff_plain;f=src%2Finspect.c;h=be98b0ddaf4cec718639ef813642f5f301c47f84;hb=3a84e0784e1e3ab7b56850d0f8c9aa42f1ae3da1;hp=ac2050c69491aee8dad3642c6a973275495ad823;hpb=c2f2a2c6769be908b25b0946f39770d09bb6ddc9;p=libguestfs.git diff --git a/src/inspect.c b/src/inspect.c index ac2050c..be98b0d 100644 --- a/src/inspect.c +++ b/src/inspect.c @@ -1,5 +1,5 @@ /* libguestfs - * Copyright (C) 2010 Red Hat Inc. + * Copyright (C) 2010-2011 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 @@ -25,6 +25,8 @@ #include #include #include +#include +#include #ifdef HAVE_PCRE #include @@ -106,11 +108,11 @@ compile_regexps (void) COMPILE (re_fedora, "Fedora release (\\d+)", 0); COMPILE (re_rhel_old, - "(?:Red Hat Enterprise Linux|CentOS|Scientific Linux).*release (\\d+).*Update (\\d+)", 0); + "(?:Red Hat|CentOS|Scientific Linux).*release (\\d+).*Update (\\d+)", 0); COMPILE (re_rhel, - "(?:Red Hat Enterprise Linux|CentOS|Scientific Linux).*release (\\d+)\\.(\\d+)", 0); + "(?:Red Hat|CentOS|Scientific Linux).*release (\\d+)\\.(\\d+)", 0); COMPILE (re_rhel_no_minor, - "(?:Red Hat Enterprise Linux|CentOS|Scientific Linux).*release (\\d+)", 0); + "(?:Red Hat|CentOS|Scientific Linux).*release (\\d+)", 0); COMPILE (re_major_minor, "(\\d+)\\.(\\d+)", 0); COMPILE (re_aug_seq, "/\\d+$", 0); COMPILE (re_xdev, "^/dev/(?:h|s|v|xv)d([a-z]\\d*)$", 0); @@ -229,7 +231,10 @@ static int check_windows_root (guestfs_h *g, struct inspect_fs *fs); static int check_windows_arch (guestfs_h *g, struct inspect_fs *fs); static int check_windows_software_registry (guestfs_h *g, struct inspect_fs *fs); static int check_windows_system_registry (guestfs_h *g, struct inspect_fs *fs); -static char *resolve_windows_path_silently (guestfs_h *g, const char *); +static char *map_registry_disk_blob (guestfs_h *g, const char *blob); +static char *case_sensitive_path_silently (guestfs_h *g, const char *); +static int is_file_nocase (guestfs_h *g, const char *); +static int is_dir_nocase (guestfs_h *g, const char *); static int extend_fses (guestfs_h *g); static int parse_unsigned_int (guestfs_h *g, const char *str); static int parse_unsigned_int_ignore_trailing (guestfs_h *g, const char *str); @@ -258,10 +263,9 @@ check_for_filesystem_on (guestfs_h *g, const char *device, int is_swap = vfs_type && STREQ (vfs_type, "swap"); - if (g->verbose) - fprintf (stderr, "check_for_filesystem_on: %s %d %d (%s)\n", - device, is_block, is_partnum, - vfs_type ? vfs_type : "failed to get vfs type"); + debug (g, "check_for_filesystem_on: %s %d %d (%s)", + device, is_block, is_partnum, + vfs_type ? vfs_type : "failed to get vfs type"); if (is_swap) { free (vfs_type); @@ -365,24 +369,31 @@ check_filesystem (guestfs_h *g, const char *device, guestfs_is_dir (g, "/run") > 0 && guestfs_is_dir (g, "/spool") > 0) fs->content = FS_CONTENT_LINUX_VAR; - /* Windows root? */ - else if (guestfs_is_file (g, "/AUTOEXEC.BAT") > 0 || - guestfs_is_file (g, "/autoexec.bat") > 0 || - guestfs_is_dir (g, "/Program Files") > 0 || - guestfs_is_dir (g, "/WINDOWS") > 0 || - guestfs_is_dir (g, "/Windows") > 0 || - guestfs_is_dir (g, "/windows") > 0 || - guestfs_is_dir (g, "/WIN32") > 0 || - guestfs_is_dir (g, "/Win32") > 0 || - guestfs_is_dir (g, "/WINNT") > 0 || - guestfs_is_file (g, "/boot.ini") > 0 || - guestfs_is_file (g, "/ntldr") > 0) { + /* Windows root? + * Note that if a Windows guest has multiple disks and applications + * are installed on those other disks, then those other disks will + * contain "/Program Files" and "/System Volume Information". Those + * would *not* be Windows root disks. (RHBZ#674130) + */ + else if (is_file_nocase (g, "/AUTOEXEC.BAT") > 0 || + is_dir_nocase (g, "/WINDOWS") > 0 || + is_dir_nocase (g, "/WIN32") > 0 || + is_dir_nocase (g, "/WINNT") > 0 || + is_file_nocase (g, "/boot.ini") > 0 || + is_file_nocase (g, "/ntldr") > 0) { fs->is_root = 1; fs->content = FS_CONTENT_WINDOWS_ROOT; fs->format = OS_FORMAT_INSTALLED; if (check_windows_root (g, fs) == -1) return -1; } + /* Windows volume with installed applications (but not root)? */ + else if (is_dir_nocase (g, "/System Volume Information") > 0 && + is_dir_nocase (g, "/Program Files") > 0) + fs->content = FS_CONTENT_WINDOWS_VOLUME_WITH_APPS; + /* Windows volume (but not root)? */ + else if (is_dir_nocase (g, "/System Volume Information") > 0) + fs->content = FS_CONTENT_WINDOWS_VOLUME; /* Install CD/disk? Skip these checks if it's not a whole device * (eg. CD) or the first partition (eg. bootable USB key). */ @@ -637,6 +648,15 @@ check_linux_root (guestfs_h *g, struct inspect_fs *fs) if (parse_major_minor (g, fs) == -1) return -1; } + else if (guestfs_exists (g, "/etc/slackware-version") > 0) { + fs->distro = OS_DISTRO_SLACKWARE; + + if (parse_release_file (g, fs, "/etc/slackware-version") == -1) + return -1; + + if (parse_major_minor (g, fs) == -1) + return -1; + } skip_release_checks:; @@ -1307,8 +1327,7 @@ add_fstab_entry (guestfs_h *g, struct inspect_fs *fs, fs->fstab[n-1].device = device; fs->fstab[n-1].mountpoint = mountpoint; - if (g->verbose) - fprintf (stderr, "fstab: device=%s mountpoint=%s\n", device, mountpoint); + debug (g, "fstab: device=%s mountpoint=%s", device, mountpoint); return 0; } @@ -1406,7 +1425,7 @@ check_windows_root (guestfs_h *g, struct inspect_fs *fs) for (i = 0; systemroot == NULL && i < sizeof systemroots / sizeof systemroots[0]; ++i) { - systemroot = resolve_windows_path_silently (g, systemroots[i]); + systemroot = case_sensitive_path_silently (g, systemroots[i]); } if (!systemroot) { @@ -1414,8 +1433,7 @@ check_windows_root (guestfs_h *g, struct inspect_fs *fs) return -1; } - if (g->verbose) - fprintf (stderr, "windows %%SYSTEMROOT%% = %s", systemroot); + debug (g, "windows %%SYSTEMROOT%% = %s", systemroot); /* Freed by guestfs___free_inspect_info. */ fs->windows_systemroot = systemroot; @@ -1444,7 +1462,7 @@ check_windows_arch (guestfs_h *g, struct inspect_fs *fs) char cmd_exe[len]; snprintf (cmd_exe, len, "%s/system32/cmd.exe", fs->windows_systemroot); - char *cmd_exe_path = resolve_windows_path_silently (g, cmd_exe); + char *cmd_exe_path = case_sensitive_path_silently (g, cmd_exe); if (!cmd_exe_path) return 0; @@ -1471,7 +1489,7 @@ check_windows_software_registry (guestfs_h *g, struct inspect_fs *fs) snprintf (software, len, "%s/system32/config/software", fs->windows_systemroot); - char *software_path = resolve_windows_path_silently (g, software); + char *software_path = case_sensitive_path_silently (g, software); if (!software_path) /* If the software hive doesn't exist, just accept that we cannot * find product_name etc. @@ -1552,6 +1570,14 @@ check_windows_software_registry (guestfs_h *g, struct inspect_fs *fs) free (version); } + else if (STRCASEEQ (key, "InstallationType")) { + fs->product_variant = hivex_value_string (h, values[i]); + if (!fs->product_variant) { + perrorf (g, "hivex_value_string"); + free (key); + goto out; + } + } free (key); } @@ -1580,7 +1606,7 @@ check_windows_system_registry (guestfs_h *g, struct inspect_fs *fs) snprintf (system, len, "%s/system32/config/system", fs->windows_systemroot); - char *system_path = resolve_windows_path_silently (g, system); + char *system_path = case_sensitive_path_silently (g, system); if (!system_path) /* If the system hive doesn't exist, just accept that we cannot * find hostname etc. @@ -1589,7 +1615,10 @@ check_windows_system_registry (guestfs_h *g, struct inspect_fs *fs) int ret = -1; hive_h *h = NULL; - hive_value_h *values = NULL; + hive_node_h root, node; + hive_value_h value, *values = NULL; + int32_t dword; + size_t i, count; if (download_to_tmp (g, system_path, system_local, MAX_REGISTRY_SIZE) == -1) goto out; @@ -1600,21 +1629,112 @@ check_windows_system_registry (guestfs_h *g, struct inspect_fs *fs) goto out; } - hive_node_h node = hivex_root (h); - /* XXX Don't hard-code ControlSet001. The current control set would - * be another good thing to expose up through the inspection API. + root = hivex_root (h); + if (root == 0) { + perrorf (g, "hivex_root"); + goto out; + } + + /* Get the CurrentControlSet. */ + errno = 0; + node = hivex_node_get_child (h, root, "Select"); + if (node == 0) { + if (errno != 0) + perrorf (g, "hivex_node_get_child"); + else + error (g, "hivex: could not locate HKLM\\SYSTEM\\Select"); + goto out; + } + + errno = 0; + value = hivex_node_get_value (h, node, "Current"); + if (value == 0) { + if (errno != 0) + perrorf (g, "hivex_node_get_value"); + else + error (g, "hivex: HKLM\\System\\Select Default entry not found."); + goto out; + } + + /* XXX Should check the type. */ + dword = hivex_value_dword (h, value); + fs->windows_current_control_set = safe_asprintf (g, "ControlSet%03d", dword); + + /* Get the drive mappings. + * This page explains the contents of HKLM\System\MountedDevices: + * http://www.goodells.net/multiboot/partsigs.shtml + */ + errno = 0; + node = hivex_node_get_child (h, root, "MountedDevices"); + if (node == 0) { + if (errno != 0) + perrorf (g, "hivex_node_get_child"); + else + error (g, "hivex: could not locate HKLM\\SYSTEM\\MountedDevices"); + goto out; + } + + values = hivex_node_values (h, node); + + /* Count how many DOS drive letter mappings there are. This doesn't + * ignore removable devices, so it overestimates, but that doesn't + * matter because it just means we'll allocate a few bytes extra. */ + for (i = count = 0; values[i] != 0; ++i) { + char *key = hivex_value_key (h, values[i]); + if (key == NULL) { + perrorf (g, "hivex_value_key"); + goto out; + } + if (STRCASEEQLEN (key, "\\DosDevices\\", 12) && + c_isalpha (key[12]) && key[13] == ':') + count++; + } + + fs->drive_mappings = calloc (2*count + 1, sizeof (char *)); + if (fs->drive_mappings == NULL) { + perrorf (g, "calloc"); + goto out; + } + + for (i = count = 0; values[i] != 0; ++i) { + char *key = hivex_value_key (h, values[i]); + if (key == NULL) { + perrorf (g, "hivex_value_key"); + goto out; + } + if (STRCASEEQLEN (key, "\\DosDevices\\", 12) && + c_isalpha (key[12]) && key[13] == ':') { + /* Get the binary value. Is it a fixed disk? */ + char *blob, *device; + size_t len; + hive_type type; + + blob = hivex_value_value (h, values[i], &type, &len); + if (blob != NULL && type == 3 && len == 12) { + /* Try to map the blob to a known disk and partition. */ + device = map_registry_disk_blob (g, blob); + if (device != NULL) { + fs->drive_mappings[count++] = safe_strndup (g, &key[12], 1); + fs->drive_mappings[count++] = device; + } + } + free (blob); + } + } + + /* Get the hostname. */ const char *hivepath[] = - { "ControlSet001", "Services", "Tcpip", "Parameters" }; - size_t i; - for (i = 0; + { fs->windows_current_control_set, "Services", "Tcpip", "Parameters" }; + for (node = root, i = 0; node != 0 && i < sizeof hivepath / sizeof hivepath[0]; ++i) { node = hivex_node_get_child (h, node, hivepath[i]); } if (node == 0) { - perrorf (g, "hivex: cannot locate HKLM\\SYSTEM\\ControlSet001\\Services\\Tcpip\\Parameters"); + perrorf (g, "hivex: cannot locate HKLM\\SYSTEM\\%s\\Services\\Tcpip\\Parameters", + fs->windows_current_control_set); goto out; } @@ -1654,8 +1774,77 @@ check_windows_system_registry (guestfs_h *g, struct inspect_fs *fs) return ret; } +/* Windows Registry HKLM\SYSTEM\MountedDevices uses a blob of data + * to store partitions. This blob is described here: + * http://www.goodells.net/multiboot/partsigs.shtml + * The following function maps this blob to a libguestfs partition + * name, if possible. + */ +static char * +map_registry_disk_blob (guestfs_h *g, const char *blob) +{ + char **devices = NULL; + struct guestfs_partition_list *partitions = NULL; + char *diskid; + size_t i, j, len; + char *ret = NULL; + uint64_t part_offset; + + /* First 4 bytes are the disk ID. Search all devices to find the + * disk with this disk ID. + */ + devices = guestfs_list_devices (g); + if (devices == NULL) + goto out; + + for (i = 0; devices[i] != NULL; ++i) { + /* Read the disk ID. */ + diskid = guestfs_pread_device (g, devices[i], 4, 0x01b8, &len); + if (diskid == NULL) + continue; + if (len < 4) { + free (diskid); + continue; + } + if (memcmp (diskid, blob, 4) == 0) { /* found it */ + free (diskid); + goto found_disk; + } + free (diskid); + } + goto out; + + found_disk: + /* Next 8 bytes are the offset of the partition in bytes(!) given as + * a 64 bit little endian number. Luckily it's easy to get the + * partition byte offset from guestfs_part_list. + */ + part_offset = le64toh (* (uint64_t *) &blob[4]); + + partitions = guestfs_part_list (g, devices[i]); + if (partitions == NULL) + goto out; + + for (j = 0; j < partitions->len; ++j) { + if (partitions->val[j].part_start == part_offset) /* found it */ + goto found_partition; + } + goto out; + + found_partition: + /* Construct the full device name. */ + ret = safe_asprintf (g, "%s%d", devices[i], partitions->val[j].part_num); + + out: + if (devices) + guestfs___free_string_list (devices); + if (partitions) + guestfs_free_partition_list (partitions); + return ret; +} + static char * -resolve_windows_path_silently (guestfs_h *g, const char *path) +case_sensitive_path_silently (guestfs_h *g, const char *path) { guestfs_error_handler_cb old_error_cb = g->error_cb; g->error_cb = NULL; @@ -1665,6 +1854,34 @@ resolve_windows_path_silently (guestfs_h *g, const char *path) } static int +is_file_nocase (guestfs_h *g, const char *path) +{ + char *p; + int r; + + p = case_sensitive_path_silently (g, path); + if (!p) + return 0; + r = guestfs_is_file (g, p); + free (p); + return r > 0; +} + +static int +is_dir_nocase (guestfs_h *g, const char *path) +{ + char *p; + int r; + + p = case_sensitive_path_silently (g, path); + if (!p) + return 0; + r = guestfs_is_dir (g, p); + free (p); + return r > 0; +} + +static int extend_fses (guestfs_h *g) { size_t n = g->nr_fses + 1; @@ -1742,6 +1959,7 @@ check_package_format (guestfs_h *g, struct inspect_fs *fs) fs->package_format = OS_PACKAGE_FORMAT_PISI; break; + case OS_DISTRO_SLACKWARE: case OS_DISTRO_WINDOWS: case OS_DISTRO_UNKNOWN: default: @@ -1786,6 +2004,7 @@ check_package_management (guestfs_h *g, struct inspect_fs *fs) fs->package_management = OS_PACKAGE_MANAGEMENT_URPMI; break; + case OS_DISTRO_SLACKWARE: case OS_DISTRO_WINDOWS: case OS_DISTRO_UNKNOWN: default: @@ -1893,6 +2112,7 @@ guestfs__inspect_get_distro (guestfs_h *g, const char *root) case OS_DISTRO_PARDUS: ret = safe_strdup (g, "pardus"); break; case OS_DISTRO_REDHAT_BASED: ret = safe_strdup (g, "redhat-based"); break; case OS_DISTRO_RHEL: ret = safe_strdup (g, "rhel"); break; + case OS_DISTRO_SLACKWARE: ret = safe_strdup (g, "slackware"); break; case OS_DISTRO_WINDOWS: ret = safe_strdup (g, "windows"); break; case OS_DISTRO_UBUNTU: ret = safe_strdup (g, "ubuntu"); break; case OS_DISTRO_UNKNOWN: default: ret = safe_strdup (g, "unknown"); break; @@ -1932,6 +2152,16 @@ guestfs__inspect_get_product_name (guestfs_h *g, const char *root) } char * +guestfs__inspect_get_product_variant (guestfs_h *g, const char *root) +{ + struct inspect_fs *fs = search_for_root (g, root); + if (!fs) + return NULL; + + return safe_strdup (g, fs->product_variant ? : "unknown"); +} + +char * guestfs__inspect_get_windows_systemroot (guestfs_h *g, const char *root) { struct inspect_fs *fs = search_for_root (g, root); @@ -1947,6 +2177,22 @@ guestfs__inspect_get_windows_systemroot (guestfs_h *g, const char *root) } char * +guestfs__inspect_get_windows_current_control_set (guestfs_h *g, + const char *root) +{ + struct inspect_fs *fs = search_for_root (g, root); + if (!fs) + return NULL; + + if (!fs->windows_current_control_set) { + error (g, _("not a Windows guest, or CurrentControlSet could not be determined")); + return NULL; + } + + return safe_strdup (g, fs->windows_current_control_set); +} + +char * guestfs__inspect_get_format (guestfs_h *g, const char *root) { struct inspect_fs *fs = search_for_root (g, root); @@ -2066,6 +2312,42 @@ guestfs__inspect_get_filesystems (guestfs_h *g, const char *root) return ret; } +char ** +guestfs__inspect_get_drive_mappings (guestfs_h *g, const char *root) +{ + char **ret; + size_t i, count; + struct inspect_fs *fs; + + fs = search_for_root (g, root); + if (!fs) + return NULL; + + /* If no drive mappings, return an empty hashtable. */ + if (!fs->drive_mappings) + count = 0; + else { + for (count = 0; fs->drive_mappings[count] != NULL; count++) + ; + } + + ret = calloc (count+1, sizeof (char *)); + if (ret == NULL) { + perrorf (g, "calloc"); + return NULL; + } + + /* We need to make a deep copy of the hashtable since the caller + * will free it. + */ + for (i = 0; i < count; ++i) + ret[i] = safe_strdup (g, fs->drive_mappings[i]); + + ret[count] = NULL; + + return ret; +} + char * guestfs__inspect_get_package_format (guestfs_h *g, const char *root) { @@ -2219,8 +2501,7 @@ list_applications_rpm (guestfs_h *g, struct inspect_fs *fs) snprintf (cmd, cmd_len, DB_DUMP " -p '%s'", tmpfile); - if (g->verbose) - fprintf (stderr, "list_applications_rpm: %s\n", cmd); + debug (g, "list_applications_rpm: %s", cmd); pp = popen (cmd, "r"); if (pp == NULL) { @@ -2397,66 +2678,95 @@ list_applications_deb (guestfs_h *g, struct inspect_fs *fs) return ret; } -/* XXX We already download the SOFTWARE hive when doing general - * inspection. We could avoid this second download of the same file - * by caching these entries in the handle. - */ +static void list_applications_windows_from_path (guestfs_h *g, hive_h *h, struct guestfs_application_list *apps, const char **path, size_t path_len); + static struct guestfs_application_list * list_applications_windows (guestfs_h *g, struct inspect_fs *fs) { TMP_TEMPLATE_ON_STACK (software_local); + /* XXX We already download the SOFTWARE hive when doing general + * inspection. We could avoid this second download of the same file + * by caching these entries in the handle. + */ size_t len = strlen (fs->windows_systemroot) + 64; char software[len]; snprintf (software, len, "%s/system32/config/software", fs->windows_systemroot); - char *software_path = resolve_windows_path_silently (g, software); + char *software_path = case_sensitive_path_silently (g, software); if (!software_path) /* If the software hive doesn't exist, just accept that we cannot * find product_name etc. */ return 0; - struct guestfs_application_list *apps = NULL, *ret = NULL; + struct guestfs_application_list *ret = NULL; hive_h *h = NULL; - hive_node_h *children = NULL; if (download_to_tmp (g, software_path, software_local, MAX_REGISTRY_SIZE) == -1) goto out; + free (software_path); + software_path = NULL; + h = hivex_open (software_local, g->verbose ? HIVEX_OPEN_VERBOSE : 0); if (h == NULL) { perrorf (g, "hivex_open"); goto out; } - hive_node_h node = hivex_root (h); + /* Allocate apps list. */ + ret = safe_malloc (g, sizeof *ret); + ret->len = 0; + ret->val = NULL; + + /* Ordinary native applications. */ const char *hivepath[] = { "Microsoft", "Windows", "CurrentVersion", "Uninstall" }; + list_applications_windows_from_path (g, h, ret, hivepath, + sizeof hivepath / sizeof hivepath[0]); + + /* 32-bit emulated Windows apps running on the WOW64 emulator. + * http://support.microsoft.com/kb/896459 (RHBZ#692545). + */ + const char *hivepath2[] = + { "WOW6432node", "Microsoft", "Windows", "CurrentVersion", "Uninstall" }; + list_applications_windows_from_path (g, h, ret, hivepath2, + sizeof hivepath2 / sizeof hivepath2[0]); + + out: + if (h) hivex_close (h); + free (software_path); + + /* Delete the temporary file. */ + unlink (software_local); +#undef software_local_len + + return ret; +} + +static void +list_applications_windows_from_path (guestfs_h *g, hive_h *h, + struct guestfs_application_list *apps, + const char **path, size_t path_len) +{ + hive_node_h *children = NULL; + hive_node_h node; size_t i; - for (i = 0; - node != 0 && i < sizeof hivepath / sizeof hivepath[0]; - ++i) { - node = hivex_node_get_child (h, node, hivepath[i]); - } - if (node == 0) { - perrorf (g, "hivex: cannot locate HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall"); - goto out; - } + node = hivex_root (h); - children = hivex_node_children (h, node); - if (children == NULL) { - perrorf (g, "hivex_node_children"); - goto out; - } + for (i = 0; node != 0 && i < path_len; ++i) + node = hivex_node_get_child (h, node, path[i]); - /* Allocate 'apps' list. */ - apps = safe_malloc (g, sizeof *apps); - apps->len = 0; - apps->val = NULL; + if (node == 0) + return; + + children = hivex_node_children (h, node); + if (children == NULL) + return; /* Consider any child node that has a DisplayName key. * See also: @@ -2476,10 +2786,8 @@ list_applications_windows (guestfs_h *g, struct inspect_fs *fs) * display name is not language-independent, so it cannot be used. */ name = hivex_node_name (h, children[i]); - if (name == NULL) { - perrorf (g, "hivex_node_get_name"); - goto out; - } + if (name == NULL) + continue; value = hivex_node_get_value (h, children[i], "DisplayName"); if (value) { @@ -2520,20 +2828,7 @@ list_applications_windows (guestfs_h *g, struct inspect_fs *fs) free (comments); } - ret = apps; - - out: - if (ret == NULL && apps != NULL) - guestfs_free_application_list (apps); - if (h) hivex_close (h); free (children); - free (software_path); - - /* Free up the temporary file. */ - unlink (software_local); -#undef software_local_len - - return ret; } static void @@ -2817,11 +3112,24 @@ guestfs__inspect_get_product_name (guestfs_h *g, const char *root) } char * +guestfs__inspect_get_product_variant (guestfs_h *g, const char *root) +{ + NOT_IMPL(NULL); +} + +char * guestfs__inspect_get_windows_systemroot (guestfs_h *g, const char *root) { NOT_IMPL(NULL); } +char * +guestfs__inspect_get_windows_current_control_set (guestfs_h *g, + const char *root) +{ + NOT_IMPL(NULL); +} + char ** guestfs__inspect_get_mountpoints (guestfs_h *g, const char *root) { @@ -2834,6 +3142,12 @@ guestfs__inspect_get_filesystems (guestfs_h *g, const char *root) NOT_IMPL(NULL); } +char ** +guestfs__inspect_get_drive_mappings (guestfs_h *g, const char *root) +{ + NOT_IMPL(NULL); +} + char * guestfs__inspect_get_package_format (guestfs_h *g, const char *root) { @@ -2858,6 +3172,30 @@ guestfs__inspect_list_applications (guestfs_h *g, const char *root) NOT_IMPL(NULL); } +char * +guestfs__inspect_get_format (guestfs_h *g, const char *root) +{ + NOT_IMPL(NULL); +} + +int +guestfs__inspect_is_live (guestfs_h *g, const char *root) +{ + NOT_IMPL(-1); +} + +int +guestfs__inspect_is_netinst (guestfs_h *g, const char *root) +{ + NOT_IMPL(-1); +} + +int +guestfs__inspect_is_multipart (guestfs_h *g, const char *root) +{ + NOT_IMPL(-1); +} + #endif /* no PCRE or hivex at compile time */ void @@ -2867,15 +3205,19 @@ guestfs___free_inspect_info (guestfs_h *g) for (i = 0; i < g->nr_fses; ++i) { free (g->fses[i].device); free (g->fses[i].product_name); + free (g->fses[i].product_variant); free (g->fses[i].arch); free (g->fses[i].hostname); free (g->fses[i].windows_systemroot); + free (g->fses[i].windows_current_control_set); size_t j; for (j = 0; j < g->fses[i].nr_fstab; ++j) { free (g->fses[i].fstab[j].device); free (g->fses[i].fstab[j].mountpoint); } free (g->fses[i].fstab); + if (g->fses[i].drive_mappings) + guestfs___free_string_list (g->fses[i].drive_mappings); } free (g->fses); g->nr_fses = 0; @@ -2916,7 +3258,7 @@ guestfs___match (guestfs_h *g, const char *str, const pcre *re) return 0; if (r != 1) { /* Internal error -- should not happen. */ - fprintf (stderr, "libguestfs: %s: %s: internal error: pcre_exec returned unexpected error code %d when matching against the string \"%s\"\n", + warning (g, "%s: %s: pcre_exec returned unexpected error code %d when matching against the string \"%s\"\n", __FILE__, __func__, r, str); return 0; } @@ -2939,7 +3281,7 @@ guestfs___match1 (guestfs_h *g, const char *str, const pcre *re) return NULL; if (r != 2) { /* Internal error -- should not happen. */ - fprintf (stderr, "libguestfs: %s: %s: internal error: pcre_exec returned unexpected error code %d when matching against the string \"%s\"\n", + warning (g, "%s: %s: internal error: pcre_exec returned unexpected error code %d when matching against the string \"%s\"", __FILE__, __func__, r, str); return NULL; } @@ -2960,7 +3302,7 @@ guestfs___match2 (guestfs_h *g, const char *str, const pcre *re, return 0; if (r != 3) { /* Internal error -- should not happen. */ - fprintf (stderr, "libguestfs: %s: %s: internal error: pcre_exec returned unexpected error code %d when matching against the string \"%s\"\n", + warning (g, "%s: %s: internal error: pcre_exec returned unexpected error code %d when matching against the string \"%s\"", __FILE__, __func__, r, str); return 0; } @@ -2984,7 +3326,7 @@ guestfs___match3 (guestfs_h *g, const char *str, const pcre *re, return 0; if (r != 4) { /* Internal error -- should not happen. */ - fprintf (stderr, "libguestfs: %s: %s: internal error: pcre_exec returned unexpected error code %d when matching against the string \"%s\"\n", + warning (g, "%s: %s: internal error: pcre_exec returned unexpected error code %d when matching against the string \"%s\"", __FILE__, __func__, r, str); return 0; }