Matthew Booth
2013-Jun-05 15:56 UTC
[Libguestfs] [PATCH 1/3] inspection: Refactor windows systemroot detection to allow re-use
This change refactors guestfs___has_windows_systemroot to guestfs___get_windows_systemroot. The new function returns a dynamically allocated char * which must be freed. The new function is no less efficient than before, as it returns the result of guestfs___case_sensitive_path_silently, which is required anyway. The new code is slightly more efficient than before, as it re-uses the result of this testing in guestfs___check_windows_root rather than running it again. --- src/guestfs-internal.h | 4 +-- src/inspect-fs-windows.c | 72 +++++++++++++++++++++++------------------------- src/inspect-fs.c | 8 ++++-- 3 files changed, 43 insertions(+), 41 deletions(-) diff --git a/src/guestfs-internal.h b/src/guestfs-internal.h index 6e97948..bc13b3c 100644 --- a/src/guestfs-internal.h +++ b/src/guestfs-internal.h @@ -668,8 +668,8 @@ extern int guestfs___check_hurd_root (guestfs_h *g, struct inspect_fs *fs); /* inspect-fs-windows.c */ extern char *guestfs___case_sensitive_path_silently (guestfs_h *g, const char *); -extern int guestfs___has_windows_systemroot (guestfs_h *g); -extern int guestfs___check_windows_root (guestfs_h *g, struct inspect_fs *fs); +extern char * guestfs___get_windows_systemroot (guestfs_h *g); +extern int guestfs___check_windows_root (guestfs_h *g, struct inspect_fs *fs, char *windows_systemroot); /* inspect-fs-cd.c */ extern int guestfs___check_installer_root (guestfs_h *g, struct inspect_fs *fs); diff --git a/src/inspect-fs-windows.c b/src/inspect-fs-windows.c index a979775..8ddea95 100644 --- a/src/inspect-fs-windows.c +++ b/src/inspect-fs-windows.c @@ -101,60 +101,58 @@ static char *map_registry_disk_blob (guestfs_h *g, const void *blob); * "/Program Files" and "/System Volume Information". Those would * *not* be Windows root disks. (RHBZ#674130) */ -static const char *systemroots[] - { "/windows", "/winnt", "/win32", "/win", NULL }; -int -guestfs___has_windows_systemroot (guestfs_h *g) +static int is_systemroot (guestfs_h *const g, const char *const systemroot) { - size_t i; char path[256]; - for (i = 0; i < sizeof systemroots / sizeof systemroots[0]; ++i) { - CLEANUP_FREE char *systemroot - guestfs___case_sensitive_path_silently (g, systemroots[i]); - if (!systemroot) - continue; + snprintf (path, sizeof path, "%s/system32", systemroot); + if (!guestfs___is_dir_nocase (g, path)) + return 0; - snprintf (path, sizeof path, "%s/system32", systemroot); - if (!guestfs___is_dir_nocase (g, path)) - continue; + snprintf (path, sizeof path, "%s/system32/config", systemroot); + if (!guestfs___is_dir_nocase (g, path)) + return 0; - snprintf (path, sizeof path, "%s/system32/config", systemroot); - if (!guestfs___is_dir_nocase (g, path)) - continue; + snprintf (path, sizeof path, "%s/system32/cmd.exe", systemroot); + if (!guestfs___is_file_nocase (g, path)) + return 0; + + return 1; +} + +char * +guestfs___get_windows_systemroot (guestfs_h *g) +{ + /* Check a predefined list of common windows system root locations */ + static const char *systemroots[] + { "/windows", "/winnt", "/win32", "/win", NULL }; - snprintf (path, sizeof path, "%s/system32/cmd.exe", systemroot); - if (!guestfs___is_file_nocase (g, path)) + for (size_t i = 0; i < sizeof systemroots / sizeof systemroots[0]; ++i) { + char *systemroot + guestfs___case_sensitive_path_silently (g, systemroots[i]); + if (!systemroot) continue; - return (int)i; + if (is_systemroot (g, systemroot)) { + debug (g, "windows %%SYSTEMROOT%% = %s", systemroot); + + return systemroot; + } else { + free (systemroot); + } } - return -1; /* not found */ + return NULL; /* not found */ } int -guestfs___check_windows_root (guestfs_h *g, struct inspect_fs *fs) +guestfs___check_windows_root (guestfs_h *g, struct inspect_fs *fs, + char *const systemroot) { - int i; - char *systemroot; - fs->type = OS_TYPE_WINDOWS; fs->distro = OS_DISTRO_WINDOWS; - i = guestfs___has_windows_systemroot (g); - if (i == -1) { - error (g, "check_windows_root: has_windows_systemroot unexpectedly returned -1"); - return -1; - } - - systemroot = guestfs_case_sensitive_path (g, systemroots[i]); - if (!systemroot) - return -1; - - debug (g, "windows %%SYSTEMROOT%% = %s", systemroot); - /* Freed by guestfs___free_inspect_info. */ fs->windows_systemroot = systemroot; @@ -179,7 +177,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); - /* Should exist because of previous check above in has_windows_systemroot. */ + /* Should exist because of previous check above in get_windows_systemroot. */ CLEANUP_FREE char *cmd_exe_path = guestfs_case_sensitive_path (g, cmd_exe); if (!cmd_exe_path) return -1; diff --git a/src/inspect-fs.c b/src/inspect-fs.c index d220634..0473e92 100644 --- a/src/inspect-fs.c +++ b/src/inspect-fs.c @@ -175,6 +175,9 @@ check_filesystem (guestfs_h *g, const char *mountable, const struct guestfs_internal_mountable *m, int whole_device) { + /* Not CLEANUP_FREE, as it will be cleaned up with inspection info */ + char *windows_systemroot = NULL; + if (extend_fses (g) == -1) return -1; @@ -274,10 +277,11 @@ check_filesystem (guestfs_h *g, const char *mountable, guestfs_is_dir (g, "/spool") > 0) ; /* Windows root? */ - else if (guestfs___has_windows_systemroot (g) >= 0) { + else if ((windows_systemroot = guestfs___get_windows_systemroot (g)) != NULL) + { fs->is_root = 1; fs->format = OS_FORMAT_INSTALLED; - if (guestfs___check_windows_root (g, fs) == -1) + if (guestfs___check_windows_root (g, fs, windows_systemroot) == -1) return -1; } /* Windows volume with installed applications (but not root)? */ -- 1.8.2.1
Matthew Booth
2013-Jun-05 15:56 UTC
[Libguestfs] [PATCH 2/3] inspect: Add internal match6 function
--- src/guestfs-internal.h | 2 ++ src/match.c | 32 +++++++++++++++++++++++++++++++- 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/src/guestfs-internal.h b/src/guestfs-internal.h index bc13b3c..0d76d1f 100644 --- a/src/guestfs-internal.h +++ b/src/guestfs-internal.h @@ -589,11 +589,13 @@ extern int guestfs___match (guestfs_h *g, const char *str, const pcre *re); extern char *guestfs___match1 (guestfs_h *g, const char *str, const pcre *re); extern int guestfs___match2 (guestfs_h *g, const char *str, const pcre *re, char **ret1, char **ret2); extern int guestfs___match3 (guestfs_h *g, const char *str, const pcre *re, char **ret1, char **ret2, char **ret3); +extern int guestfs___match6 (guestfs_h *g, const char *str, const pcre *re, char **ret1, char **ret2, char **ret3, char **ret4, char **ret5, char **ret6); #define match guestfs___match #define match1 guestfs___match1 #define match2 guestfs___match2 #define match3 guestfs___match3 +#define match6 guestfs___match6 /* proto.c */ extern int guestfs___send (guestfs_h *g, int proc_nr, uint64_t progress_hint, uint64_t optargs_bitmask, xdrproc_t xdrp, char *args); diff --git a/src/match.c b/src/match.c index b31721c..86c0a31 100644 --- a/src/match.c +++ b/src/match.c @@ -1,5 +1,5 @@ /* libguestfs - * Copyright (C) 2010-2012 Red Hat Inc. + * Copyright (C) 2010-2013 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 @@ -103,3 +103,33 @@ guestfs___match3 (guestfs_h *g, const char *str, const pcre *re, return 1; } + +/* Match a regular expression which contains exactly six captures. */ +int +guestfs___match6 (guestfs_h *g, const char *str, const pcre *re, + char **ret1, char **ret2, char **ret3, char **ret4, + char **ret5, char **ret6) +{ + size_t len = strlen (str); + int vec[30], r; + + r = pcre_exec (re, NULL, str, len, 0, 0, vec, 30); + if (r == PCRE_ERROR_NOMATCH) + return 0; + + *ret1 = NULL; + *ret2 = NULL; + *ret3 = NULL; + *ret4 = NULL; + *ret5 = NULL; + *ret6 = NULL; + + if (r > 1) *ret1 = safe_strndup (g, &str[vec[2]], vec[3]-vec[2]); + if (r > 2) *ret2 = safe_strndup (g, &str[vec[4]], vec[5]-vec[4]); + if (r > 3) *ret3 = safe_strndup (g, &str[vec[6]], vec[7]-vec[6]); + if (r > 4) *ret4 = safe_strndup (g, &str[vec[8]], vec[9]-vec[8]); + if (r > 5) *ret5 = safe_strndup (g, &str[vec[10]], vec[11]-vec[10]); + if (r > 6) *ret6 = safe_strndup (g, &str[vec[12]], vec[13]-vec[12]); + + return 1; +} -- 1.8.2.1
Matthew Booth
2013-Jun-05 15:56 UTC
[Libguestfs] [PATCH 3/3] inspect: Partial support for non-standard windows system root
Support arbitrary windows system root for pre-vista systems where boot.ini is on the same partition as the system root. --- src/inspect-fs-windows.c | 86 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/src/inspect-fs-windows.c b/src/inspect-fs-windows.c index 8ddea95..61b2f3b 100644 --- a/src/inspect-fs-windows.c +++ b/src/inspect-fs-windows.c @@ -50,6 +50,8 @@ * simultaneously. */ static pcre *re_windows_version; +static pcre *re_boot_ini_os_header; +static pcre *re_boot_ini_os; static void compile_regexps (void) __attribute__((constructor)); static void free_regexps (void) __attribute__((destructor)); @@ -70,12 +72,16 @@ compile_regexps (void) } while (0) COMPILE (re_windows_version, "^(\\d+)\\.(\\d+)", 0); + COMPILE (re_boot_ini_os_header, "^\\[operating systems\\]\\s*$", 0); + COMPILE (re_boot_ini_os, "^(multi|scsi)\\((\\d+)\\)disk\\((\\d+)\\)rdisk\\((\\d+)\\)partition\\((\\d+)\\)([^=]+)=", 0); } static void free_regexps (void) { pcre_free (re_windows_version); + pcre_free (re_boot_ini_os_header); + pcre_free (re_boot_ini_os); } static int check_windows_arch (guestfs_h *g, struct inspect_fs *fs); @@ -143,6 +149,86 @@ guestfs___get_windows_systemroot (guestfs_h *g) } } + /* If the fs contains boot.ini, check it for non-standard + * systemroot locations */ + CLEANUP_FREE char *boot_ini_path + guestfs___case_sensitive_path_silently (g, "/boot.ini"); + if (boot_ini_path) { + CLEANUP_FREE_STRING_LIST char **boot_ini + guestfs_read_lines (g, boot_ini_path); + if (!boot_ini) { + debug (g, "error reading %s", boot_ini_path); + return NULL; + } + + int found_os = 0; + for (char **i = boot_ini; *i != NULL; i++) { + CLEANUP_FREE char *controller_type = NULL; + CLEANUP_FREE char *controller = NULL; + CLEANUP_FREE char *disk = NULL; + CLEANUP_FREE char *rdisk = NULL; + CLEANUP_FREE char *partition = NULL; + CLEANUP_FREE char *path = NULL; + + char *line = *i; + + if (!found_os) { + if (match (g, line, re_boot_ini_os_header)) { + found_os = 1; + continue; + } + } + + /* See http://support.microsoft.com/kb/102873 for a discussion + * of what this line means */ + if (match6 (g, line, re_boot_ini_os, &controller_type, + &controller, &disk, &rdisk, &partition, &path)) + { + /* The Windows system root may be on any disk. However, there + * are currently (at least) 2 practical problems preventing us + * from locating it on another disk: + * + * 1. We don't have enough metadata about the disks we were + * given to know if what controller they were on and what + * index they had. + * + * 2. The way inspection of filesystems currently works, we + * can't mark another filesystem, which we may have already + * inspected, to be inspected for a specific Windows system + * root. + * + * Solving 1 properly would require a new API at a minimum. We + * might be able to fudge something practical without this, + * though, e.g. by looking at the <partition>th partition of + * every disk for the specific windows root. + * + * Solving 2 would probably require a significant refactoring + * of the way filesystems are inspected. We should probably do + * this some time. + * + * For the moment, we ignore all partition information and + * assume the system root is on the current partition. In + * practice, this will normally be correct. + */ + + /* Swap backslashes for forward slashes in the system root + * path */ + for (char *j = path; *j != '\0'; j++) { + if (*j == '\\') *j = '/'; + } + + char *systemroot = guestfs___case_sensitive_path_silently (g, path); + if (systemroot && is_systemroot (g, systemroot)) { + debug (g, "windows %%SYSTEMROOT%% = %s", systemroot); + + return systemroot; + } else { + free (systemroot); + } + } + } + } + return NULL; /* not found */ } -- 1.8.2.1
Richard W.M. Jones
2013-Jun-05 17:05 UTC
Re: [Libguestfs] [PATCH 3/3] inspect: Partial support for non-standard windows system root
On Wed, Jun 05, 2013 at 04:56:03PM +0100, Matthew Booth wrote:> Support arbitrary windows system root for pre-vista systems where > boot.ini is on the same partition as the system root.^^^^^^^^^^^^^^^^^^^^^ I was just coming back to make this point. Is this a common configuration? All the guests I can remember have had a separate boot partition, except Windows XP. Anyway, it seems this is an improvement, and there are no obvious problems and it passes make check & make check-valgrind, so I have pushed it. Rich. -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones virt-df lists disk usage of guests without needing to install any software inside the virtual machine. Supports Linux and Windows. http://people.redhat.com/~rjones/virt-df/
Apparently Analagous Threads
- [PATCH v2] inspection: Fix calls to case_sensitive_path (RHBZ#858126).
- [PATCH] inspector: add /reactos as systemroot
- [PATCH 3/3] inspect: Partial support for non-standard windows system root
- [PATCH] inspect: Fix bogus warning for partitions without /boot.ini
- [PATCH] inspector: add ReactOS systemroot