X-Git-Url: http://git.annexia.org/?a=blobdiff_plain;f=src%2Finspect.c;h=238e6e517a2ad2e63e61685648dfc4269a32be2b;hb=1bf970cb0e7fc0f9d8c10b567c6c7b4a66e43c17;hp=7cf18c345421904f014b35950046a30e3376a6c6;hpb=4e0cf4dbf8a8a96288f70114fdc3939da0aa7ad1;p=libguestfs.git diff --git a/src/inspect.c b/src/inspect.c index 7cf18c3..238e6e5 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 @@ -230,6 +230,8 @@ 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 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); @@ -364,24 +366,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). */ @@ -636,6 +645,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:; @@ -1549,6 +1567,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); } @@ -1662,6 +1688,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 = resolve_windows_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 = resolve_windows_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; @@ -1739,6 +1793,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: @@ -1783,6 +1838,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: @@ -1890,6 +1946,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; @@ -1929,6 +1986,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); @@ -2393,15 +2460,17 @@ 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", @@ -2414,45 +2483,72 @@ list_applications_windows (guestfs_h *g, struct inspect_fs *fs) */ 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: @@ -2472,10 +2568,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) { @@ -2516,20 +2610,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 @@ -2813,6 +2894,12 @@ 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); @@ -2887,6 +2974,7 @@ 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);