X-Git-Url: http://git.annexia.org/?a=blobdiff_plain;f=src%2Finspect.c;h=900b6f41970046a77b31dda3d866929fe79c3b1f;hb=c018c39cc9dfe2d7bf923a87d5c71e96654499ba;hp=baf4b3a015a80c897768f1f591aff8b6cf75a46e;hpb=fab75c0337d7897d10ea5e95e47ac05eab81ace9;p=libguestfs.git diff --git a/src/inspect.c b/src/inspect.c index baf4b3a..900b6f4 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 @@ -45,6 +45,31 @@ #if defined(HAVE_PCRE) && defined(HAVE_HIVEX) +/* Some limits on what we will read, for safety. */ + +/* Small text configuration files. + * + * The upper limit is for general files that we grep or download. The + * largest such file is probably "txtsetup.sif" from Windows CDs + * (~500K). This number has to be larger than any legitimate file and + * smaller than the protocol message size. + * + * The lower limit is for files parsed by Augeas on the daemon side, + * where Augeas is running in reduced memory and can potentially + * create a lot of metadata so we really need to be careful about + * those. + */ +#define MAX_SMALL_FILE_SIZE (2 * 1000 * 1000) +#define MAX_AUGEAS_FILE_SIZE (100 * 1000) + +/* Maximum Windows Registry hive that we will download to /tmp. Some + * registries can be legitimately very large. + */ +#define MAX_REGISTRY_SIZE (100 * 1000 * 1000) + +/* Maximum RPM or dpkg database we will download to /tmp. */ +#define MAX_PKG_DB_SIZE (10 * 1000 * 1000) + /* Compile all the regular expressions once when the shared library is * loaded. PCRE is thread safe so we're supposedly OK here if * multiple threads call into the libguestfs API functions below @@ -81,11 +106,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); @@ -203,7 +228,9 @@ 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 *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 add_fstab_entry (guestfs_h *g, struct inspect_fs *fs, @@ -326,23 +353,30 @@ 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; 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; return 0; } @@ -417,7 +451,7 @@ parse_lsb_release (guestfs_h *g, struct inspect_fs *fs) if (size == -1) /* guestfs_filesize failed and has already set error in handle */ return -1; - if (size > 1000000) { + if (size > MAX_SMALL_FILE_SIZE) { error (g, _("size of %s is unreasonably large (%" PRIi64 " bytes)"), filename, size); return -1; @@ -609,8 +643,6 @@ check_linux_root (guestfs_h *g, struct inspect_fs *fs) static int check_freebsd_root (guestfs_h *g, struct inspect_fs *fs) { - int r; - fs->type = OS_TYPE_FREEBSD; /* FreeBSD has no authoritative version file. The version number is @@ -673,8 +705,6 @@ check_architecture (guestfs_h *g, struct inspect_fs *fs) static int check_hostname_unix (guestfs_h *g, struct inspect_fs *fs) { - char **lines; - switch (fs->type) { case OS_TYPE_LINUX: /* Red Hat-derived would be in /etc/sysconfig/network, and @@ -757,7 +787,7 @@ check_hostname_freebsd (guestfs_h *g, struct inspect_fs *fs) if (size == -1) /* guestfs_filesize failed and has already set error in handle */ return -1; - if (size > 1000000) { + if (size > MAX_SMALL_FILE_SIZE) { error (g, _("size of %s is unreasonably large (%" PRIi64 " bytes)"), filename, size); return -1; @@ -1004,7 +1034,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) { @@ -1042,7 +1072,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; @@ -1069,7 +1099,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. @@ -1080,7 +1110,8 @@ check_windows_software_registry (guestfs_h *g, struct inspect_fs *fs) hive_h *h = NULL; hive_value_h *values = NULL; - if (download_to_tmp (g, software_path, software_local, 100000000) == -1) + if (download_to_tmp (g, software_path, software_local, + MAX_REGISTRY_SIZE) == -1) goto out; h = hivex_open (software_local, g->verbose ? HIVEX_OPEN_VERBOSE : 0); @@ -1177,7 +1208,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. @@ -1188,7 +1219,7 @@ check_windows_system_registry (guestfs_h *g, struct inspect_fs *fs) hive_h *h = NULL; hive_value_h *values = NULL; - if (download_to_tmp (g, system_path, system_local, 100000000) == -1) + if (download_to_tmp (g, system_path, system_local, MAX_REGISTRY_SIZE) == -1) goto out; h = hivex_open (system_local, g->verbose ? HIVEX_OPEN_VERBOSE : 0); @@ -1252,7 +1283,7 @@ check_windows_system_registry (guestfs_h *g, struct inspect_fs *fs) } 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; @@ -1262,6 +1293,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; @@ -1661,7 +1720,9 @@ guestfs__inspect_get_hostname (guestfs_h *g, const char *root) return safe_strdup (g, fs->hostname ? : "unknown"); } +#ifdef DB_DUMP static struct guestfs_application_list *list_applications_rpm (guestfs_h *g, struct inspect_fs *fs); +#endif static struct guestfs_application_list *list_applications_deb (guestfs_h *g, struct inspect_fs *fs); static struct guestfs_application_list *list_applications_windows (guestfs_h *g, struct inspect_fs *fs); static void add_application (guestfs_h *g, struct guestfs_application_list *, const char *name, const char *display_name, int32_t epoch, const char *version, const char *release, const char *install_path, const char *publisher, const char *url, const char *description); @@ -1683,9 +1744,11 @@ guestfs__inspect_list_applications (guestfs_h *g, const char *root) case OS_TYPE_LINUX: switch (fs->package_format) { case OS_PACKAGE_FORMAT_RPM: +#ifdef DB_DUMP ret = list_applications_rpm (g, fs); if (ret == NULL) return NULL; +#endif break; case OS_PACKAGE_FORMAT_DEB: @@ -1729,12 +1792,13 @@ guestfs__inspect_list_applications (guestfs_h *g, const char *root) return ret; } +#ifdef DB_DUMP static struct guestfs_application_list * list_applications_rpm (guestfs_h *g, struct inspect_fs *fs) { TMP_TEMPLATE_ON_STACK (tmpfile); - if (download_to_tmp (g, "/var/lib/rpm/Name", tmpfile, 10000000) == -1) + if (download_to_tmp (g, "/var/lib/rpm/Name", tmpfile, MAX_PKG_DB_SIZE) == -1) return NULL; struct guestfs_application_list *apps = NULL, *ret = NULL; @@ -1744,7 +1808,7 @@ list_applications_rpm (guestfs_h *g, struct inspect_fs *fs) char line[1024]; size_t len; - snprintf (cmd, cmd_len, "db_dump -p '%s'", tmpfile); + snprintf (cmd, cmd_len, DB_DUMP " -p '%s'", tmpfile); if (g->verbose) fprintf (stderr, "list_applications_rpm: %s\n", cmd); @@ -1829,13 +1893,15 @@ list_applications_rpm (guestfs_h *g, struct inspect_fs *fs) return ret; } +#endif /* defined DB_DUMP */ static struct guestfs_application_list * list_applications_deb (guestfs_h *g, struct inspect_fs *fs) { TMP_TEMPLATE_ON_STACK (tmpfile); - if (download_to_tmp (g, "/var/lib/dpkg/status", tmpfile, 10000000) == -1) + if (download_to_tmp (g, "/var/lib/dpkg/status", tmpfile, + MAX_PKG_DB_SIZE) == -1) return NULL; struct guestfs_application_list *apps = NULL, *ret = NULL; @@ -1936,7 +2002,7 @@ list_applications_windows (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. @@ -1947,7 +2013,8 @@ list_applications_windows (guestfs_h *g, struct inspect_fs *fs) hive_h *h = NULL; hive_node_h *children = NULL; - if (download_to_tmp (g, software_path, software_local, 100000000) == -1) + if (download_to_tmp (g, software_path, software_local, + MAX_REGISTRY_SIZE) == -1) goto out; h = hivex_open (software_local, g->verbose ? HIVEX_OPEN_VERBOSE : 0); @@ -2166,7 +2233,7 @@ inspect_with_augeas (guestfs_h *g, struct inspect_fs *fs, const char *filename, if (size == -1) /* guestfs_filesize failed and has already set error in handle */ return -1; - if (size > 100000) { + if (size > MAX_AUGEAS_FILE_SIZE) { error (g, _("size of %s is unreasonably large (%" PRIi64 " bytes)"), filename, size); return -1; @@ -2216,7 +2283,7 @@ first_line_of_file (guestfs_h *g, const char *filename) if (size == -1) /* guestfs_filesize failed and has already set error in handle */ return NULL; - if (size > 1000000) { + if (size > MAX_SMALL_FILE_SIZE) { error (g, _("size of %s is unreasonably large (%" PRIi64 " bytes)"), filename, size); return NULL; @@ -2336,6 +2403,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 @@ -2346,6 +2437,7 @@ guestfs___free_inspect_info (guestfs_h *g) free (g->fses[i].device); free (g->fses[i].product_name); free (g->fses[i].arch); + free (g->fses[i].hostname); free (g->fses[i].windows_systemroot); size_t j; for (j = 0; j < g->fses[i].nr_fstab; ++j) {