static pcre *re_windows_version;
static void compile_regexps (void) __attribute__((constructor));
+static void free_regexps (void) __attribute__((destructor));
+
static void
compile_regexps (void)
{
COMPILE (re_windows_version, "^(\\d+)\\.(\\d+)", 0);
}
+static void
+free_regexps (void)
+{
+ pcre_free (re_file_elf);
+ pcre_free (re_file_win64);
+ pcre_free (re_elf_ppc64);
+ pcre_free (re_fedora);
+ pcre_free (re_rhel_old);
+ pcre_free (re_rhel);
+ pcre_free (re_rhel_no_minor);
+ pcre_free (re_debian);
+ pcre_free (re_aug_seq);
+ pcre_free (re_xdev);
+ pcre_free (re_windows_version);
+}
+
/* Match a regular expression which contains no captures. Returns
* true if it matches or false if it doesn't.
*/
static char *
cpio_arch (guestfs_h *g, const char *file, const char *path)
{
+ TMP_TEMPLATE_ON_STACK (dir);
+#define dir_len (strlen (dir))
+#define initrd_len (dir_len + 16)
+ char initrd[initrd_len];
+#define cmd_len (dir_len + 256)
+ char cmd[cmd_len];
+#define bin_len (dir_len + 32)
+ char bin[bin_len];
+
char *ret = NULL;
const char *method;
else
method = "cat";
- char dir[] = "/tmp/initrd.XXXXXX";
-#define dir_len (sizeof dir)
if (mkdtemp (dir) == NULL) {
perrorf (g, "mkdtemp");
goto out;
}
- char dir_initrd[dir_len + 16];
- snprintf (dir_initrd, dir_len + 16, "%s/initrd", dir);
- if (guestfs_download (g, path, dir_initrd) == -1)
+ snprintf (initrd, initrd_len, "%s/initrd", dir);
+ if (guestfs_download (g, path, initrd) == -1)
goto out;
- char cmd[dir_len + 256];
- snprintf (cmd, dir_len + 256,
+ snprintf (cmd, cmd_len,
"cd %s && %s initrd | cpio --quiet -id " INITRD_BINARIES1,
dir, method);
int r = system (cmd);
goto out;
}
- char bin[dir_len + 32];
const char *bins[] = INITRD_BINARIES2;
size_t i;
for (i = 0; i < sizeof bins / sizeof bins[0]; ++i) {
- snprintf (bin, dir_len + 32, "%s/%s", dir, bins[i]);
+ snprintf (bin, bin_len, "%s/%s", dir, bins[i]);
if (is_regular_file (bin)) {
int flags = g->verbose ? MAGIC_DEBUG : 0;
* contain shell meta-characters because of the way it was
* constructed above.
*/
- snprintf (cmd, dir_len + 256, "rm -rf %s", dir);
+ snprintf (cmd, cmd_len, "rm -rf %s", dir);
ignore_value (system (cmd));
return ret;
#undef dir_len
+#undef initrd_len
+#undef cmd_len
+#undef bin_len
}
char *
check_windows_registry (guestfs_h *g, struct inspect_fs *fs,
const char *systemroot)
{
+ TMP_TEMPLATE_ON_STACK (dir);
+#define dir_len (strlen (dir))
+#define software_hive_len (dir_len + 16)
+ char software_hive[software_hive_len];
+#define cmd_len (dir_len + 16)
+ char cmd[cmd_len];
+
size_t len = strlen (systemroot) + 64;
char software[len];
snprintf (software, len, "%s/system32/config/software", systemroot);
hive_h *h = NULL;
hive_value_h *values = NULL;
- char dir[] = "/tmp/winreg.XXXXXX";
-#define dir_len 18
if (mkdtemp (dir) == NULL) {
perrorf (g, "mkdtemp");
goto out;
}
- char software_hive[dir_len + 16];
- snprintf (software_hive, dir_len + 16, "%s/software", dir);
+ snprintf (software_hive, software_hive_len, "%s/software", dir);
if (guestfs_download (g, software_path, software_hive) == -1)
goto out;
* contain shell meta-characters because of the way it was
* constructed above.
*/
- char cmd[dir_len + 16];
- snprintf (cmd, dir_len + 16, "rm -rf %s", dir);
+ snprintf (cmd, cmd_len, "rm -rf %s", dir);
ignore_value (system (cmd));
#undef dir_len
+#undef software_hive_len
+#undef cmd_len
return ret;
}
return ret;
}
-int
+int
guestfs__inspect_get_major_version (guestfs_h *g, const char *root)
{
struct inspect_fs *fs = search_for_root (g, root);
return fs->major_version;
}
-int
+int
guestfs__inspect_get_minor_version (guestfs_h *g, const char *root)
{
struct inspect_fs *fs = search_for_root (g, root);
return ret;
}
+
+/* List filesystems.
+ *
+ * The current implementation just uses guestfs_vfs_type and doesn't
+ * try mounting anything, but we reserve the right in future to try
+ * mounting filesystems.
+ */
+
+static void remove_from_list (char **list, const char *item);
+static void check_with_vfs_type (guestfs_h *g, const char *dev, char ***ret, size_t *ret_size);
+
+char **
+guestfs__list_filesystems (guestfs_h *g)
+{
+ size_t i;
+ char **ret;
+ size_t ret_size;
+
+ ret = safe_malloc (g, sizeof (char *));
+ ret[0] = NULL;
+ ret_size = 0;
+
+ /* Look to see if any devices directly contain filesystems
+ * (RHBZ#590167). However vfs-type will fail to tell us anything
+ * useful about devices which just contain partitions, so we also
+ * get the list of partitions and exclude the corresponding devices
+ * by using part-to-dev.
+ */
+ char **devices;
+ devices = guestfs_list_devices (g);
+ if (devices == NULL) {
+ free_string_list (ret);
+ return NULL;
+ }
+ char **partitions;
+ partitions = guestfs_list_partitions (g);
+ if (partitions == NULL) {
+ free_string_list (devices);
+ free_string_list (ret);
+ return NULL;
+ }
+
+ for (i = 0; partitions[i] != NULL; ++i) {
+ char *dev = guestfs_part_to_dev (g, partitions[i]);
+ if (dev)
+ remove_from_list (devices, dev);
+ free (dev);
+ }
+
+ /* Use vfs-type to check for filesystems on devices. */
+ for (i = 0; devices[i] != NULL; ++i)
+ check_with_vfs_type (g, devices[i], &ret, &ret_size);
+ free_string_list (devices);
+
+ /* Use vfs-type to check for filesystems on partitions. */
+ for (i = 0; partitions[i] != NULL; ++i)
+ check_with_vfs_type (g, partitions[i], &ret, &ret_size);
+ free_string_list (partitions);
+
+ if (feature_available (g, "lvm2")) {
+ /* Use vfs-type to check for filesystems on LVs. */
+ char **lvs;
+ lvs = guestfs_lvs (g);
+ if (lvs == NULL) {
+ free_string_list (ret);
+ return NULL;
+ }
+
+ for (i = 0; lvs[i] != NULL; ++i)
+ check_with_vfs_type (g, lvs[i], &ret, &ret_size);
+ free_string_list (lvs);
+ }
+
+ return ret;
+}
+
+/* If 'item' occurs in 'list', remove and free it. */
+static void
+remove_from_list (char **list, const char *item)
+{
+ size_t i;
+
+ for (i = 0; list[i] != NULL; ++i)
+ if (STREQ (list[i], item)) {
+ free (list[i]);
+ for (; list[i+1] != NULL; ++i)
+ list[i] = list[i+1];
+ list[i] = NULL;
+ return;
+ }
+}
+
+/* Use vfs-type to look for a filesystem of some sort on 'dev'.
+ * Apart from some types which we ignore, add the result to the
+ * 'ret' string list.
+ */
+static void
+check_with_vfs_type (guestfs_h *g, const char *device,
+ char ***ret, size_t *ret_size)
+{
+ char *v;
+
+ guestfs_error_handler_cb old_error_cb = g->error_cb;
+ g->error_cb = NULL;
+ char *vfs_type = guestfs_vfs_type (g, device);
+ g->error_cb = old_error_cb;
+
+ if (!vfs_type)
+ v = safe_strdup (g, "unknown");
+ else {
+ /* Ignore all "*_member" strings. In libblkid these are returned
+ * for things which are members of some RAID or LVM set, most
+ * importantly "LVM2_member" which is a PV.
+ */
+ size_t n = strlen (vfs_type);
+ if (n >= 7 && STREQ (&vfs_type[n-7], "_member")) {
+ free (vfs_type);
+ return;
+ }
+
+ /* Ignore LUKS-encrypted partitions. These are also containers. */
+ if (STREQ (vfs_type, "crypto_LUKS")) {
+ free (vfs_type);
+ return;
+ }
+
+ v = vfs_type;
+ }
+
+ /* Extend the return array. */
+ size_t i = *ret_size;
+ *ret_size += 2;
+ *ret = safe_realloc (g, *ret, (*ret_size + 1) * sizeof (char *));
+ (*ret)[i] = safe_strdup (g, device);
+ (*ret)[i+1] = v;
+ (*ret)[i+2] = NULL;
+}