/* 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 int check_with_vfs_type (guestfs_h *g, const char *device, struct stringsbuf *sb) { const char *v; CLEANUP_FREE char *vfs_type = NULL; guestfs_push_error_handler (g, NULL, NULL); vfs_type = guestfs_vfs_type (g, device); guestfs_pop_error_handler (g); if (!vfs_type) v = "unknown"; else if (STREQ (vfs_type, "")) v = "unknown"; else if (STREQ (vfs_type, "btrfs")) { CLEANUP_FREE_BTRFSSUBVOLUME_LIST struct guestfs_btrfssubvolume_list *vols = guestfs_btrfs_subvolume_list (g, device); if (vols == NULL) return -1; for (size_t i = 0; i < vols->len; i++) { struct guestfs_btrfssubvolume *this = &vols->val[i]; guestfs_int_add_sprintf (g, sb, "btrfsvol:%s/%s", device, this->btrfssubvolume_path); guestfs_int_add_string (g, sb, "btrfs"); } v = vfs_type; }
/* Simple implementation of decryption: look for any crypto_LUKS * partitions and decrypt them, then rescan for VGs. This only works * for Fedora whole-disk encryption. WIP to make this work for other * encryption schemes. */ void inspect_do_decrypt (void) { CLEANUP_FREE_STRING_LIST char **partitions = guestfs_list_partitions (g); if (partitions == NULL) exit (EXIT_FAILURE); int need_rescan = 0; size_t i; for (i = 0; partitions[i] != NULL; ++i) { CLEANUP_FREE char *type = guestfs_vfs_type (g, partitions[i]); if (type && STREQ (type, "crypto_LUKS")) { char mapname[32]; make_mapname (partitions[i], mapname, sizeof mapname); CLEANUP_FREE char *key = read_key (partitions[i]); /* XXX Should we call guestfs_luks_open_ro if readonly flag * is set? This might break 'mount_ro'. */ if (guestfs_luks_open (g, partitions[i], key, mapname) == -1) exit (EXIT_FAILURE); need_rescan = 1; } } if (need_rescan) { if (guestfs_vgscan (g) == -1) exit (EXIT_FAILURE); if (guestfs_vg_activate_all (g, 1) == -1) exit (EXIT_FAILURE); } }
/* 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; char *vfs_type; guestfs_push_error_handler (g, NULL, NULL); vfs_type = guestfs_vfs_type (g, device); guestfs_pop_error_handler (g); if (!vfs_type) v = safe_strdup (g, "unknown"); else if (STREQ (vfs_type, "")) { v = safe_strdup (g, "unknown"); free (vfs_type); } else if (STREQ (vfs_type, "btrfs")) { CLEANUP_FREE_BTRFSSUBVOLUME_LIST struct guestfs_btrfssubvolume_list *vols = guestfs_btrfs_subvolume_list (g, device); for (size_t i = 0; i < vols->len; i++) { struct guestfs_btrfssubvolume *this = &vols->val[i]; char *mountable = safe_asprintf (g, "btrfsvol:%s/%s", device, this->btrfssubvolume_path); add_vfs (g, mountable, safe_strdup (g, "btrfs"), ret, ret_size); } v = vfs_type; }
static void output_filesystems (xmlTextWriterPtr xo, char *root) { char *str; size_t i; CLEANUP_FREE_STRING_LIST char **filesystems = guestfs_inspect_get_filesystems (g, root); if (filesystems == NULL) exit (EXIT_FAILURE); /* Sort by name so the output is stable. */ qsort (filesystems, guestfs_int_count_strings (filesystems), sizeof (char *), compare_keys); XMLERROR (-1, xmlTextWriterStartElement (xo, BAD_CAST "filesystems")); for (i = 0; filesystems[i] != NULL; ++i) { str = guestfs_canonical_device_name (g, filesystems[i]); if (!str) exit (EXIT_FAILURE); XMLERROR (-1, xmlTextWriterStartElement (xo, BAD_CAST "filesystem")); XMLERROR (-1, xmlTextWriterWriteAttribute (xo, BAD_CAST "dev", BAD_CAST str)); free (str); guestfs_push_error_handler (g, NULL, NULL); str = guestfs_vfs_type (g, filesystems[i]); if (str && str[0]) XMLERROR (-1, xmlTextWriterWriteElement (xo, BAD_CAST "type", BAD_CAST str)); free (str); str = guestfs_vfs_label (g, filesystems[i]); if (str && str[0]) XMLERROR (-1, xmlTextWriterWriteElement (xo, BAD_CAST "label", BAD_CAST str)); free (str); str = guestfs_vfs_uuid (g, filesystems[i]); if (str && str[0]) XMLERROR (-1, xmlTextWriterWriteElement (xo, BAD_CAST "uuid", BAD_CAST str)); free (str); guestfs_pop_error_handler (g); XMLERROR (-1, xmlTextWriterEndElement (xo)); } XMLERROR (-1, xmlTextWriterEndElement (xo)); }
/* 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 if (STREQ (vfs_type, "")) { free (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; }
/* 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 int check_with_vfs_type (guestfs_h *g, const char *device, struct stringsbuf *sb) { const char *v; CLEANUP_FREE char *vfs_type = NULL; guestfs_push_error_handler (g, NULL, NULL); vfs_type = guestfs_vfs_type (g, device); guestfs_pop_error_handler (g); if (!vfs_type) v = "unknown"; else if (STREQ (vfs_type, "")) v = "unknown"; else if (STREQ (vfs_type, "btrfs")) { CLEANUP_FREE_BTRFSSUBVOLUME_LIST struct guestfs_btrfssubvolume_list *vols = guestfs_btrfs_subvolume_list (g, device); if (vols == NULL) return -1; int64_t default_volume = guestfs_btrfs_subvolume_get_default (g, device); for (size_t i = 0; i < vols->len; i++) { struct guestfs_btrfssubvolume *this = &vols->val[i]; /* Ignore the default subvolume. We get it by simply mounting * the whole device of this btrfs filesystem. */ if (this->btrfssubvolume_id == (uint64_t) default_volume) continue; guestfs_int_add_sprintf (g, sb, "btrfsvol:%s/%s", device, this->btrfssubvolume_path); guestfs_int_add_string (g, sb, "btrfs"); } v = vfs_type; }
/* Find out if 'device' contains a filesystem. If it does, add * another entry in g->fses. */ int guestfs_int_check_for_filesystem_on (guestfs_h *g, const char *mountable) { CLEANUP_FREE char *vfs_type = NULL; int is_swap, r; struct inspect_fs *fs; CLEANUP_FREE_INTERNAL_MOUNTABLE struct guestfs_internal_mountable *m = NULL; int whole_device = 0; /* Get vfs-type in order to check if it's a Linux(?) swap device. * If there's an error we should ignore it, so to do that we have to * temporarily replace the error handler with a null one. */ guestfs_push_error_handler (g, NULL, NULL); vfs_type = guestfs_vfs_type (g, mountable); guestfs_pop_error_handler (g); is_swap = vfs_type && STREQ (vfs_type, "swap"); debug (g, "check_for_filesystem_on: %s (%s)", mountable, vfs_type ? vfs_type : "failed to get vfs type"); if (is_swap) { extend_fses (g); fs = &g->fses[g->nr_fses-1]; fs->mountable = safe_strdup (g, mountable); return 0; } m = guestfs_internal_parse_mountable (g, mountable); if (m == NULL) return -1; /* If it's a whole device, see if it is an install ISO. */ if (m->im_type == MOUNTABLE_DEVICE) { whole_device = guestfs_is_whole_device (g, m->im_device); if (whole_device == -1) { return -1; } } if (whole_device) { extend_fses (g); fs = &g->fses[g->nr_fses-1]; r = guestfs_int_check_installer_iso (g, fs, m->im_device); if (r == -1) { /* Fatal error. */ g->nr_fses--; return -1; } if (r > 0) /* Found something. */ return 0; /* Didn't find anything. Fall through ... */ g->nr_fses--; } /* Try mounting the device. As above, ignore errors. */ guestfs_push_error_handler (g, NULL, NULL); if (vfs_type && STREQ (vfs_type, "ufs")) { /* Hack for the *BSDs. */ /* FreeBSD fs is a variant of ufs called ufs2 ... */ r = guestfs_mount_vfs (g, "ro,ufstype=ufs2", "ufs", mountable, "/"); if (r == -1) /* while NetBSD and OpenBSD use another variant labeled 44bsd */ r = guestfs_mount_vfs (g, "ro,ufstype=44bsd", "ufs", mountable, "/"); } else { r = guestfs_mount_ro (g, mountable, "/"); } guestfs_pop_error_handler (g); if (r == -1) return 0; /* Do the rest of the checks. */ r = check_filesystem (g, mountable, m, whole_device); /* Unmount the filesystem. */ if (guestfs_umount_all (g) == -1) return -1; return r; }