static void read_all (guestfs_h *g, void *retv, const char *buf, size_t len) { char **ret = retv; *ret = safe_strndup (g, buf, len); }
/* Match a regular expression which contains exactly two captures. */ int guestfs___match2 (guestfs_h *g, const char *str, const pcre *re, char **ret1, char **ret2) { 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; 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]); return 1; }
/* Match a regular expression which contains exactly one capture. If * the string matches, return the capture, otherwise return NULL. The * caller must free the result. */ char * guestfs___match1 (guestfs_h *g, const char *str, const pcre *re) { size_t len = strlen (str); int vec[30], r; r = pcre_exec (re, NULL, str, len, 0, 0, vec, sizeof vec / sizeof vec[0]); if (r == PCRE_ERROR_NOMATCH) return NULL; return r == 2 ? safe_strndup (g, &str[vec[2]], vec[3]-vec[2]) : NULL; }
/* 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; }
/* Parse the hostname from /etc/rc.conf. On FreeBSD this file * contains comments, blank lines and: * hostname="freebsd8.example.com" * ifconfig_re0="DHCP" * keymap="uk.iso" * sshd_enable="YES" */ static int check_hostname_freebsd (guestfs_h *g, struct inspect_fs *fs) { const char *filename = "/etc/rc.conf"; int64_t size; CLEANUP_FREE_STRING_LIST char **lines = NULL; size_t i; /* Don't trust guestfs_read_lines not to break with very large files. * Check the file size is something reasonable first. */ size = guestfs_filesize (g, filename); if (size == -1) /* guestfs_filesize failed and has already set error in handle */ return -1; if (size > MAX_SMALL_FILE_SIZE) { error (g, _("size of %s is unreasonably large (%" PRIi64 " bytes)"), filename, size); return -1; } lines = guestfs_read_lines (g, filename); if (lines == NULL) return -1; for (i = 0; lines[i] != NULL; ++i) { if (STRPREFIX (lines[i], "hostname=\"") || STRPREFIX (lines[i], "hostname='")) { size_t len = strlen (lines[i]) - 10 - 1; fs->hostname = safe_strndup (g, &lines[i][10], len); break; } else if (STRPREFIX (lines[i], "hostname=")) { size_t len = strlen (lines[i]) - 9; fs->hostname = safe_strndup (g, &lines[i][9], len); break; } } return 0; }
/* Like 'add_cmdline' but allowing a shell-quoted string of zero or * more options. XXX The unquoting is not very clever. */ static void add_cmdline_shell_unquoted (guestfs_h *g, struct stringsbuf *sb, const char *options) { char quote; const char *startp, *endp, *nextp; while (*options) { quote = *options; if (quote == '\'' || quote == '"') startp = options+1; else { startp = options; quote = ' '; } endp = strchr (options, quote); if (endp == NULL) { if (quote != ' ') { fprintf (stderr, _("unclosed quote character (%c) in command line near: %s"), quote, options); _exit (EXIT_FAILURE); } endp = options + strlen (options); } if (quote == ' ') { if (endp[0] == '\0') nextp = endp; else nextp = endp+1; } else { if (!endp[1]) nextp = endp+1; else if (endp[1] == ' ') nextp = endp+2; else { fprintf (stderr, _("cannot parse quoted string near: %s"), options); _exit (EXIT_FAILURE); } } while (*nextp && *nextp == ' ') nextp++; guestfs___add_string_nodup (g, sb, safe_strndup (g, startp, endp-startp)); options = nextp; } }
/* Search elements of g->path, returning the first path element which * matches the predicate function 'pred'. * * Function 'pred' must return a true or false value. If it returns * -1 then the entire search is aborted. * * Return values: * 1 = a path element matched, it is returned in *pelem_ret and must be * freed by the caller, * 0 = no path element matched, *pelem_ret is set to NULL, or * -1 = error which aborts the launch process */ static int find_path (guestfs_h *g, int (*pred) (guestfs_h *g, const char *pelem, void *data), void *data, char **pelem_ret) { size_t len; int r; const char *pelem = g->path; /* Note that if g->path is an empty string, we want to check the * current directory (for backwards compatibility with * libguestfs < 1.5.4). */ do { len = strcspn (pelem, PATH_SEPARATOR); /* Empty element or "." means current directory. */ if (len == 0) *pelem_ret = safe_strdup (g, "."); else *pelem_ret = safe_strndup (g, pelem, len); r = pred (g, *pelem_ret, data); if (r == -1) { free (*pelem_ret); return -1; } if (r != 0) /* predicate matched */ return 1; free (*pelem_ret); if (pelem[len] == PATH_SEPARATOR[0]) pelem += len + 1; else pelem += len; } while (*pelem); /* Predicate didn't match on any path element. */ *pelem_ret = NULL; return 0; }
char * guestfs_impl_disk_format (guestfs_h *g, const char *filename) { CLEANUP_JSON_T_DECREF json_t *tree = get_json_output (g, filename); json_t *node; if (tree == NULL) return NULL; if (!json_is_object (tree)) goto bad_type; node = json_object_get (tree, "format"); if (!json_is_string (node)) goto bad_type; return safe_strndup (g, json_string_value (node), json_string_length (node)); /* caller frees */ bad_type: error (g, _("qemu-img info: JSON output did not contain ‘format’ key")); return NULL; }
static int check_windows_system_registry (guestfs_h *g, struct inspect_fs *fs) { int r; size_t len = strlen (fs->windows_systemroot) + 64; char system[len]; snprintf (system, len, "%s/system32/config/system", fs->windows_systemroot); CLEANUP_FREE char *system_path = guestfs_case_sensitive_path (g, system); if (!system_path) return -1; r = guestfs_is_file (g, system_path); if (r == -1) return -1; /* If the system hive doesn't exist, just accept that we cannot * find hostname etc. */ if (r == 0) return 0; int ret = -1; int64_t root, node, value; CLEANUP_FREE_HIVEX_VALUE_LIST struct guestfs_hivex_value_list *values = NULL; CLEANUP_FREE_HIVEX_VALUE_LIST struct guestfs_hivex_value_list *values2 = NULL; int32_t dword; size_t i, count; CLEANUP_FREE void *buf = NULL; size_t buflen; const char *hivepath[] = { NULL /* current control set */, "Services", "Tcpip", "Parameters" }; if (guestfs_hivex_open (g, system_path, GUESTFS_HIVEX_OPEN_VERBOSE, g->verbose, -1) == -1) goto out; root = guestfs_hivex_root (g); if (root == 0) goto out; /* Get the CurrentControlSet. */ node = guestfs_hivex_node_get_child (g, root, "Select"); if (node == -1) goto out; if (node == 0) { error (g, "hivex: could not locate HKLM\\SYSTEM\\Select"); goto out; } value = guestfs_hivex_node_get_value (g, node, "Current"); if (value == -1) goto out; if (value == 0) { error (g, "hivex: HKLM\\System\\Select Default entry not found"); goto out; } /* XXX Should check the type. */ buf = guestfs_hivex_value_value (g, value, &buflen); if (buflen != 4) { error (g, "hivex: HKLM\\System\\Select\\Current expected to be DWORD"); goto out; } dword = le32toh (*(int32_t *)buf); 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 */ node = guestfs_hivex_node_get_child (g, root, "MountedDevices"); if (node == -1) goto out; if (node == 0) /* Not found: skip getting drive letter mappings (RHBZ#803664). */ goto skip_drive_letter_mappings; values = guestfs_hivex_node_values (g, 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; i < values->len; ++i) { CLEANUP_FREE char *key = guestfs_hivex_value_key (g, values->val[i].hivex_value_h); if (key == NULL) goto out; if (STRCASEEQLEN (key, "\\DosDevices\\", 12) && c_isalpha (key[12]) && key[13] == ':') count++; } fs->drive_mappings = safe_calloc (g, 2*count + 1, sizeof (char *)); for (i = count = 0; i < values->len; ++i) { int64_t v = values->val[i].hivex_value_h; CLEANUP_FREE char *key = guestfs_hivex_value_key (g, v); if (key == NULL) goto out; if (STRCASEEQLEN (key, "\\DosDevices\\", 12) && c_isalpha (key[12]) && key[13] == ':') { /* Get the binary value. Is it a fixed disk? */ CLEANUP_FREE char *blob = NULL; char *device; size_t len; int64_t type; type = guestfs_hivex_value_type (g, v); blob = guestfs_hivex_value_value (g, v, &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; } } } } skip_drive_letter_mappings:; /* Get the hostname. */ hivepath[0] = fs->windows_current_control_set; for (node = root, i = 0; node > 0 && i < sizeof hivepath / sizeof hivepath[0]; ++i) { node = guestfs_hivex_node_get_child (g, node, hivepath[i]); } if (node == -1) goto out; if (node == 0) { perrorf (g, "hivex: cannot locate HKLM\\SYSTEM\\%s\\Services\\Tcpip\\Parameters", fs->windows_current_control_set); goto out; } values2 = guestfs_hivex_node_values (g, node); if (values2 == NULL) goto out; for (i = 0; i < values2->len; ++i) { int64_t v = values2->val[i].hivex_value_h; CLEANUP_FREE char *key = guestfs_hivex_value_key (g, v); if (key == NULL) goto out; if (STRCASEEQ (key, "Hostname")) { fs->hostname = guestfs_hivex_value_utf8 (g, v); if (!fs->hostname) goto out; } /* many other interesting fields here ... */ } ret = 0; out: guestfs_hivex_close (g); return ret; }
/* Ubuntu has /etc/lsb-release containing: * DISTRIB_ID=Ubuntu # Distro * DISTRIB_RELEASE=10.04 # Version * DISTRIB_CODENAME=lucid * DISTRIB_DESCRIPTION="Ubuntu 10.04.1 LTS" # Product name * * [Ubuntu-derived ...] Linux Mint was found to have this: * DISTRIB_ID=LinuxMint * DISTRIB_RELEASE=10 * DISTRIB_CODENAME=julia * DISTRIB_DESCRIPTION="Linux Mint 10 Julia" * Linux Mint also has /etc/linuxmint/info with more information, * but we can use the LSB file. * * Mandriva has: * LSB_VERSION=lsb-4.0-amd64:lsb-4.0-noarch * DISTRIB_ID=MandrivaLinux * DISTRIB_RELEASE=2010.1 * DISTRIB_CODENAME=Henry_Farman * DISTRIB_DESCRIPTION="Mandriva Linux 2010.1" * Mandriva also has a normal release file called /etc/mandriva-release. */ static int parse_lsb_release (guestfs_h *g, struct inspect_fs *fs) { const char *filename = "/etc/lsb-release"; int64_t size; CLEANUP_FREE_STRING_LIST char **lines = NULL; size_t i; int r = 0; /* Don't trust guestfs_head_n not to break with very large files. * Check the file size is something reasonable first. */ size = guestfs_filesize (g, filename); if (size == -1) /* guestfs_filesize failed and has already set error in handle */ return -1; if (size > MAX_SMALL_FILE_SIZE) { error (g, _("size of %s is unreasonably large (%" PRIi64 " bytes)"), filename, size); return -1; } lines = guestfs_head_n (g, 10, filename); if (lines == NULL) return -1; for (i = 0; lines[i] != NULL; ++i) { if (fs->distro == 0 && STREQ (lines[i], "DISTRIB_ID=Ubuntu")) { fs->distro = OS_DISTRO_UBUNTU; r = 1; } else if (fs->distro == 0 && STREQ (lines[i], "DISTRIB_ID=LinuxMint")) { fs->distro = OS_DISTRO_LINUX_MINT; r = 1; } else if (fs->distro == 0 && STREQ (lines[i], "DISTRIB_ID=MandrivaLinux")) { fs->distro = OS_DISTRO_MANDRIVA; r = 1; } else if (fs->distro == 0 && STREQ (lines[i], "DISTRIB_ID=\"Mageia\"")) { fs->distro = OS_DISTRO_MAGEIA; r = 1; } else if (STRPREFIX (lines[i], "DISTRIB_RELEASE=")) { char *major, *minor; if (match2 (g, &lines[i][16], re_major_minor, &major, &minor)) { fs->major_version = guestfs___parse_unsigned_int (g, major); free (major); if (fs->major_version == -1) { free (minor); return -1; } fs->minor_version = guestfs___parse_unsigned_int (g, minor); free (minor); if (fs->minor_version == -1) return -1; } } else if (fs->product_name == NULL && (STRPREFIX (lines[i], "DISTRIB_DESCRIPTION=\"") || STRPREFIX (lines[i], "DISTRIB_DESCRIPTION='"))) { size_t len = strlen (lines[i]) - 21 - 1; fs->product_name = safe_strndup (g, &lines[i][21], len); r = 1; } else if (fs->product_name == NULL && STRPREFIX (lines[i], "DISTRIB_DESCRIPTION=")) { size_t len = strlen (lines[i]) - 20; fs->product_name = safe_strndup (g, &lines[i][20], len); r = 1; } } /* The unnecessary construct in the next line is required to * workaround -Wstrict-overflow warning in gcc 4.5.1. */ return r ? 1 : 0; }