static void do_output_blockdevs (void) { size_t i; CLEANUP_FREE_STRING_LIST char **devices = guestfs_list_devices (g); if (devices == NULL) exit (EXIT_FAILURE); for (i = 0; devices[i] != NULL; ++i) { int64_t size = -1; CLEANUP_FREE_STRING_LIST char **parents = NULL; CLEANUP_FREE char *dev; dev = guestfs_canonical_device_name (g, devices[i]); if (!dev) exit (EXIT_FAILURE); if ((columns & COLUMN_SIZE)) { size = guestfs_blockdev_getsize64 (g, devices[i]); if (size == -1) exit (EXIT_FAILURE); } if (is_md (devices[i])) parents = parents_of_md (devices[i]); else parents = no_parents (); write_row (dev, "device", NULL, NULL, -1, size, parents, NULL); } }
/* Perform 'df' operation on the domain(s) given in the list. */ static void multi_df (struct domain *domains, size_t n, size_t *errors_r) { size_t i; size_t nd; size_t count; int r; char **devices; char **domain_devices; /* Add all the disks to the handle (since they were added in reverse * order, we must add them here in reverse too). */ for (i = 0, count = 0; i < n; ++i) count += add_disks_to_handle_reverse (domains[i].disks, errors_r); if (count == 0) return; /* Launch the handle. */ if (guestfs_launch (g) == -1) exit (EXIT_FAILURE); devices = guestfs_list_devices (g); if (devices == NULL) exit (EXIT_FAILURE); for (i = 0, nd = 0; i < n; ++i) { /* Find out how many non-failed disks this domain has. */ count = count_non_failed_disks (domains[i].disks); if (count == 0) continue; /* Duplicate the devices into a separate list for convenience. * Note this doesn't duplicate the strings themselves. */ domain_devices = duplicate_first_n (&devices[nd], count); r = df_on_handle (domains[i].name, domains[i].uuid, domain_devices, nd); nd += count; free (domain_devices); /* Something broke in df_on_handle. Give up on the remaining * devices for this handle, but keep going on the next handle. */ if (r == -1) { (*errors_r)++; break; } } for (i = 0; devices[i] != NULL; ++i) free (devices[i]); free (devices); /* Reset the handle. */ reset_guestfs_handle (); }
/* Perform 'df' operation on the domain(s) given in the list. */ static void multi_df (struct domain *domains, size_t n) { size_t i; size_t nd; int r; char **devices; /* Add all the disks to the handle (since they were added in reverse * order, we must add them here in reverse too). */ for (i = 0; i < n; ++i) add_disks_to_handle_reverse (domains[i].disks); /* Launch the handle. */ if (guestfs_launch (g) == -1) exit (EXIT_FAILURE); devices = guestfs_list_devices (g); if (devices == NULL) exit (EXIT_FAILURE); /* Check the number of disks we think we added is the same as the * number of devices returned by libguestfs. */ nd = 0; for (i = 0; i < n; ++i) nd += domains[i].nr_disks; assert (nd == count_strings (devices)); nd = 0; for (i = 0; i < n; ++i) { /* So that &devices[nd] is a NULL-terminated list of strings. */ char *p = devices[nd + domains[i].nr_disks]; devices[nd + domains[i].nr_disks] = NULL; r = df_on_handle (domains[i].name, domains[i].uuid, &devices[nd], nd); /* Restore devices to original. */ devices[nd + domains[i].nr_disks] = p; nd += domains[i].nr_disks; /* Something broke in df_on_handle. Give up on the remaining * devices for this handle, but keep going on the next handle. */ if (r == -1) break; } for (i = 0; devices[i] != NULL; ++i) free (devices[i]); free (devices); /* Reset the handle. */ reset_guestfs_handle (); }
/* Windows Registry HKLM\SYSTEM\MountedDevices uses a blob of data * to store partitions. This blob is described here: * http://www.goodells.net/multiboot/partsigs.shtml * The following function maps this blob to a libguestfs partition * name, if possible. */ static char * map_registry_disk_blob (guestfs_h *g, const void *blob) { CLEANUP_FREE_STRING_LIST char **devices = NULL; CLEANUP_FREE_PARTITION_LIST struct guestfs_partition_list *partitions = NULL; size_t i, j, len; uint64_t part_offset; /* First 4 bytes are the disk ID. Search all devices to find the * disk with this disk ID. */ devices = guestfs_list_devices (g); if (devices == NULL) return NULL; for (i = 0; devices[i] != NULL; ++i) { /* Read the disk ID. */ CLEANUP_FREE char *diskid = guestfs_pread_device (g, devices[i], 4, 0x01b8, &len); if (diskid == NULL) continue; if (len < 4) continue; if (memcmp (diskid, blob, 4) == 0) /* found it */ goto found_disk; } return NULL; found_disk: /* Next 8 bytes are the offset of the partition in bytes(!) given as * a 64 bit little endian number. Luckily it's easy to get the * partition byte offset from guestfs_part_list. */ memcpy (&part_offset, (char *) blob + 4, sizeof (part_offset)); part_offset = le64toh (part_offset); partitions = guestfs_part_list (g, devices[i]); if (partitions == NULL) return NULL; for (j = 0; j < partitions->len; ++j) { if (partitions->val[j].part_start == part_offset) /* found it */ goto found_partition; } return NULL; found_partition: /* Construct the full device name. */ return safe_asprintf (g, "%s%d", devices[i], partitions->val[j].part_num); }
/* Since we want this function to be robust against very bad failure * cases (hello, https://bugzilla.kernel.org/show_bug.cgi?id=18792) it * won't exit on guestfs failures. */ int df_on_handle (guestfs_h *g, const char *name, const char *uuid, FILE *fp) { size_t i; CLEANUP_FREE_STRING_LIST char **devices = NULL; CLEANUP_FREE_STRING_LIST char **fses = NULL; if (verbose) fprintf (stderr, "df_on_handle: %s\n", name); devices = guestfs_list_devices (g); if (devices == NULL) return -1; fses = guestfs_list_filesystems (g); if (fses == NULL) return -1; for (i = 0; fses[i] != NULL; i += 2) { if (STRNEQ (fses[i+1], "") && STRNEQ (fses[i+1], "swap") && STRNEQ (fses[i+1], "unknown")) { const char *dev = fses[i]; CLEANUP_FREE_STATVFS struct guestfs_statvfs *stat = NULL; if (verbose) fprintf (stderr, "df_on_handle: %s dev %s\n", name, dev); /* Try mounting and stating the device. This might reasonably * fail, so don't show errors. */ guestfs_push_error_handler (g, NULL, NULL); if (guestfs_mount_ro (g, dev, "/") == 0) { stat = guestfs_statvfs (g, "/"); guestfs_umount_all (g); } guestfs_pop_error_handler (g); if (stat) print_stat (fp, name, uuid, dev, stat); } } return 0; }
static void test_block_device (void) { int fd; char tmpfile[] = "/tmp/speedtestXXXXXX"; CLEANUP_FREE char **devices = NULL; char *r; const char *argv[4]; int t = max_time_override > 0 ? max_time_override : TEST_BLOCK_DEVICE_TIME; char tbuf[64]; int64_t bytes_written, bytes_read; if (!block_device_write && !block_device_read) return; snprintf (tbuf, sizeof tbuf, "%d", t); g = guestfs_create (); if (!g) error (EXIT_FAILURE, errno, "guestfs_create"); /* Create a fully allocated backing file. Note we are not testing * the speed of allocation on the host. */ fd = mkstemp (tmpfile); if (fd == -1) error (EXIT_FAILURE, errno, "mkstemp: %s", tmpfile); close (fd); if (guestfs_disk_create (g, tmpfile, "raw", INT64_C (1024*1024*1024), GUESTFS_DISK_CREATE_PREALLOCATION, "full", -1) == -1) exit (EXIT_FAILURE); if (guestfs_add_drive (g, tmpfile) == -1) exit (EXIT_FAILURE); if (guestfs_launch (g) == -1) exit (EXIT_FAILURE); devices = guestfs_list_devices (g); if (devices == NULL) exit (EXIT_FAILURE); if (devices[0] == NULL) { fprintf (stderr, "%s: expected guestfs_list_devices to return at least 1 device\n", guestfs_int_program_name); exit (EXIT_FAILURE); } if (block_device_write) { /* Test write speed. */ argv[0] = devices[0]; argv[1] = "w"; argv[2] = tbuf; argv[3] = NULL; r = guestfs_debug (g, "device_speed", (char **) argv); if (r == NULL) exit (EXIT_FAILURE); if (sscanf (r, "%" SCNi64, &bytes_written) != 1) { fprintf (stderr, "%s: could not parse device_speed output\n", guestfs_int_program_name); exit (EXIT_FAILURE); } print_rate ("block device writes:", bytes_written / t); } if (block_device_read) { /* Test read speed. */ argv[0] = devices[0]; argv[1] = "r"; argv[2] = tbuf; argv[3] = NULL; r = guestfs_debug (g, "device_speed", (char **) argv); if (r == NULL) exit (EXIT_FAILURE); if (sscanf (r, "%" SCNi64, &bytes_read) != 1) { fprintf (stderr, "%s: could not parse device_speed output\n", guestfs_int_program_name); exit (EXIT_FAILURE); } print_rate ("block device reads:", bytes_read / t); } if (guestfs_shutdown (g) == -1) exit (EXIT_FAILURE); guestfs_close (g); /* Remove temporary file. */ unlink (tmpfile); }
void scan (size_t *worst_alignment, const char *prefix) { char **devices, *p; size_t i, j; size_t alignment; uint64_t start; struct guestfs_partition_list *parts; devices = guestfs_list_devices (g); if (devices == NULL) exit (EXIT_FAILURE); for (i = 0; devices[i] != NULL; ++i) { parts = guestfs_part_list (g, devices[i]); if (parts == NULL) exit (EXIT_FAILURE); /* Canonicalize the name of the device for printing. */ p = guestfs_canonical_device_name (g, devices[i]); if (p == NULL) exit (EXIT_FAILURE); free (devices[i]); devices[i] = p; for (j = 0; j < parts->len; ++j) { /* Start offset of the partition in bytes. */ start = parts->val[j].part_start; if (!quiet) { if (prefix) printf ("%s:", prefix); printf ("%s%d %12" PRIu64 " ", devices[i], (int) parts->val[j].part_num, start); } /* What's the alignment? */ if (start == 0) /* Probably not possible, but anyway. */ alignment = 64; else for (alignment = 0; (start & 1) == 0; alignment++, start /= 2) ; if (!quiet) { if (alignment < 10) printf ("%12" PRIu64 " ", UINT64_C(1) << alignment); else if (alignment < 64) printf ("%12" PRIu64 "K ", UINT64_C(1) << (alignment - 10)); else printf ("- "); } if (alignment < *worst_alignment) *worst_alignment = alignment; if (alignment < 12) { /* Bad in general: < 4K alignment */ if (!quiet) printf ("bad (%s)\n", _("alignment < 4K")); } else if (alignment < 16) { /* Bad on NetApps: < 64K alignment */ if (!quiet) printf ("bad (%s)\n", _("alignment < 64K")); } else { if (!quiet) printf ("ok\n"); } } guestfs_free_partition_list (parts); free (devices[i]); } free (devices); }
/* Since we want this function to be robust against very bad failure * cases (hello, https://bugzilla.kernel.org/show_bug.cgi?id=18792) it * won't exit on guestfs failures. */ int df_on_handle (const char *name, const char *uuid, char **devices, int offset) { int ret = -1; size_t i; char **fses = NULL; int free_devices = 0, is_lv; if (verbose) { fprintf (stderr, "df_on_handle %s devices=", name); if (devices) { fputc ('[', stderr); for (i = 0; devices[i] != NULL; ++i) { if (i > 0) fputc (' ', stderr); fputs (devices[i], stderr); } fputc (']', stderr); } else fprintf (stderr, "null"); fputc ('\n', stderr); } if (devices == NULL) { devices = guestfs_list_devices (g); if (devices == NULL) goto cleanup; free_devices = 1; } else { /* Mask LVM for just the devices in the set. */ if (guestfs_lvm_set_filter (g, devices) == -1) goto cleanup; } /* list-filesystems will return filesystems on every device ... */ fses = guestfs_list_filesystems (g); if (fses == NULL) goto cleanup; /* ... so we need to filter out only the devices we are interested in. */ for (i = 0; fses[i] != NULL; i += 2) { if (STRNEQ (fses[i+1], "") && STRNEQ (fses[i+1], "swap") && STRNEQ (fses[i+1], "unknown")) { is_lv = guestfs_is_lv (g, fses[i]); if (is_lv > 0) /* LVs are OK because of the LVM filter */ try_df (name, uuid, fses[i], -1); else if (is_lv == 0) { if (find_dev_in_devices (fses[i], devices)) try_df (name, uuid, fses[i], offset); } } } ret = 0; cleanup: if (fses) { for (i = 0; fses[i] != NULL; ++i) free (fses[i]); free (fses); } if (free_devices) { for (i = 0; devices[i] != NULL; ++i) free (devices[i]); free (devices); } return ret; }
char * complete_dest_paths_generator (const char *text, int state) { #ifdef HAVE_LIBREADLINE static size_t len, index; static struct word *words = NULL; static size_t nr_words = 0; guestfs_error_handler_cb old_error_cb; void *old_error_cb_data; /* Temporarily replace the error handler so that messages don't * get printed to stderr while we are issuing commands. */ #define SAVE_ERROR_CB \ old_error_cb = guestfs_get_error_handler (g, &old_error_cb_data); \ guestfs_set_error_handler (g, NULL, NULL); /* Restore error handler. */ #define RESTORE_ERROR_CB \ guestfs_set_error_handler (g, old_error_cb, old_error_cb_data); if (!state) { char **strs; len = strlen (text); index = 0; if (words) free_words (words, nr_words); words = NULL; nr_words = 0; SAVE_ERROR_CB /* Silently do nothing if an allocation fails */ #define APPEND_STRS_AND_FREE \ do { \ if (strs) { \ size_t i; \ size_t n = count_strings (strs); \ \ if ( n > 0 && ! xalloc_oversized (nr_words + n, sizeof (struct word))) { \ struct word *w; \ w = realloc (words, sizeof (struct word) * (nr_words + n)); \ \ if (w == NULL) { \ free_words (words, nr_words); \ words = NULL; \ nr_words = 0; \ } else { \ words = w; \ for (i = 0; i < n; ++i) { \ words[nr_words].name = strs[i]; \ words[nr_words].is_dir = 0; \ nr_words++; \ } \ } \ } \ free (strs); \ } \ } while (0) /* Is it a device? */ if (len < 5 || STREQLEN (text, "/dev/", 5)) { /* Get a list of everything that can possibly begin with /dev/ */ strs = guestfs_list_devices (g); APPEND_STRS_AND_FREE; strs = guestfs_list_partitions (g); APPEND_STRS_AND_FREE; strs = guestfs_lvs (g); APPEND_STRS_AND_FREE; strs = guestfs_list_dm_devices (g); APPEND_STRS_AND_FREE; strs = guestfs_list_md_devices (g); APPEND_STRS_AND_FREE; } if (len < 1 || text[0] == '/') { /* If we've got a partial path already, we need to list everything * in that directory, otherwise list everything in / */ char *p, *dir; struct guestfs_dirent_list *dirents; p = strrchr (text, '/'); dir = p && p > text ? strndup (text, p - text) : strdup ("/"); if (dir) { dirents = guestfs_readdir (g, dir); /* Prepend directory to names before adding them to the list * of words. */ if (dirents) { size_t i; for (i = 0; i < dirents->len; ++i) { int err; if (STRNEQ (dirents->val[i].name, ".") && STRNEQ (dirents->val[i].name, "..")) { if (STREQ (dir, "/")) err = asprintf (&p, "/%s", dirents->val[i].name); else err = asprintf (&p, "%s/%s", dir, dirents->val[i].name); if (err >= 0) { if (!xalloc_oversized (nr_words+1, sizeof (struct word))) { struct word *w; w = realloc (words, sizeof (struct word) * (nr_words+1)); if (w == NULL) { free_words (words, nr_words); words = NULL; nr_words = 0; } else { words = w; words[nr_words].name = p; words[nr_words].is_dir = dirents->val[i].ftyp == 'd'; nr_words++; } } } } } guestfs_free_dirent_list (dirents); } } } /* else ... In theory we could complete other things here such as VG * names. At the moment we don't do that. */ RESTORE_ERROR_CB }
/* Returns 0 on success, 1 if we need to retry. */ static int do_format (void) { char **devices; size_t i; int ret; devices = guestfs_list_devices (g); if (devices == NULL) exit (EXIT_FAILURE); /* Erase the disks. */ if (!wipe) { for (i = 0; devices[i] != NULL; ++i) { /* erase the filesystem signatures on each device */ if (have_wipefs && guestfs_wipefs (g, devices[i]) == -1) exit (EXIT_FAILURE); /* Then erase the partition table on each device. */ if (guestfs_zero (g, devices[i]) == -1) exit (EXIT_FAILURE); } } else /* wipe */ { for (i = 0; devices[i] != NULL; ++i) { if (guestfs_zero_device (g, devices[i]) == -1) exit (EXIT_FAILURE); } } if (do_rescan (devices)) { ret = 1; /* which means, reopen the handle and retry */ goto out; } /* Format each disk. */ for (i = 0; devices[i] != NULL; ++i) { char *dev = devices[i]; int free_dev = 0; if (partition) { const char *ptype = partition; int64_t dev_size; /* If partition has the magic value "DEFAULT", choose either MBR or GPT.*/ if (STREQ (partition, "DEFAULT")) { dev_size = guestfs_blockdev_getsize64 (g, devices[i]); if (dev_size == -1) exit (EXIT_FAILURE); ptype = dev_size < INT64_C(2)*1024*1024*1024*1024 ? "mbr" : "gpt"; } if (guestfs_part_disk (g, devices[i], ptype) == -1) exit (EXIT_FAILURE); if (asprintf (&dev, "%s1", devices[i]) == -1) { perror ("asprintf"); exit (EXIT_FAILURE); } free_dev = 1; } if (vg && lv) { char *devs[2] = { dev, NULL }; if (guestfs_pvcreate (g, dev) == -1) exit (EXIT_FAILURE); if (guestfs_vgcreate (g, vg, devs) == -1) exit (EXIT_FAILURE); if (guestfs_lvcreate_free (g, lv, vg, 100) == -1) exit (EXIT_FAILURE); if (free_dev) free (dev); if (asprintf (&dev, "/dev/%s/%s", vg, lv) == -1) { perror ("asprintf"); exit (EXIT_FAILURE); } free_dev = 1; } if (filesystem) { if (guestfs_mkfs_opts (g, filesystem, dev, -1) == -1) exit (EXIT_FAILURE); } if (free_dev) free (dev); } if (guestfs_sync (g) == -1) exit (EXIT_FAILURE); ret = 0; out: /* Free device list. */ for (i = 0; devices[i] != NULL; ++i) free (devices[i]); free (devices); return ret; }
char * complete_dest_paths_generator (const char *text, int state) { #ifdef HAVE_LIBREADLINE static size_t len, index; static struct word *words = NULL; static size_t nr_words = 0; if (!state) { char **strs; len = strlen (text); index = 0; if (words) free_words (words, nr_words); words = NULL; nr_words = 0; guestfs_push_error_handler (g, NULL, NULL); /* Silently do nothing if an allocation fails */ #define APPEND_STRS_AND_FREE \ do { \ if (strs) { \ size_t i; \ size_t n = count_strings (strs); \ \ if ( n > 0 && ! xalloc_oversized (nr_words + n, sizeof (struct word))) { \ struct word *w; \ w = realloc (words, sizeof (struct word) * (nr_words + n)); \ \ if (w == NULL) { \ free_words (words, nr_words); \ words = NULL; \ nr_words = 0; \ } else { \ words = w; \ for (i = 0; i < n; ++i) { \ words[nr_words].name = strs[i]; \ words[nr_words].is_dir = 0; \ nr_words++; \ } \ } \ } \ free (strs); \ } \ } while (0) /* Is it a device? */ if (len < 5 || STREQLEN (text, "/dev/", 5)) { /* Get a list of everything that can possibly begin with /dev/ */ strs = guestfs_list_devices (g); APPEND_STRS_AND_FREE; strs = guestfs_list_partitions (g); APPEND_STRS_AND_FREE; strs = guestfs_lvs (g); APPEND_STRS_AND_FREE; strs = guestfs_list_dm_devices (g); APPEND_STRS_AND_FREE; strs = guestfs_list_md_devices (g); APPEND_STRS_AND_FREE; } if (len < 1 || text[0] == '/') { /* If we've got a partial path already, we need to list everything * in that directory, otherwise list everything in / */ char *p, *dir; struct guestfs_dirent_list *dirents; p = strrchr (text, '/'); dir = p && p > text ? strndup (text, p - text) : strdup ("/"); if (dir) { dirents = guestfs_readdir (g, dir); /* Prepend directory to names before adding them to the list * of words. */ if (dirents) { size_t i; for (i = 0; i < dirents->len; ++i) { int err; if (STRNEQ (dirents->val[i].name, ".") && STRNEQ (dirents->val[i].name, "..")) { if (STREQ (dir, "/")) err = asprintf (&p, "/%s", dirents->val[i].name); else err = asprintf (&p, "%s/%s", dir, dirents->val[i].name); if (err >= 0) { if (!xalloc_oversized (nr_words+1, sizeof (struct word))) { struct word *w; w = realloc (words, sizeof (struct word) * (nr_words+1)); if (w == NULL) { free_words (words, nr_words); words = NULL; nr_words = 0; } else { words = w; words[nr_words].name = p; words[nr_words].is_dir = dirents->val[i].ftyp == 'd'; nr_words++; } } } } } guestfs_free_dirent_list (dirents); } } } /* else ... In theory we could complete other things here such as VG * names. At the moment we don't do that. */ guestfs_pop_error_handler (g); } /* This inhibits ordinary (local filename) completion. */ rl_attempted_completion_over = 1; /* Sort the words so the list is stable over multiple calls. */ if (words) qsort (words, nr_words, sizeof (struct word), compare_words); /* Complete the string. */ while (index < nr_words) { struct word *word; word = &words[index]; index++; /* Whether we should match case insensitively here or not is * determined by the value of the completion-ignore-case readline * variable. Default to case insensitive. (See: RHBZ#582993). */ char *cic_var = rl_variable_value ("completion-ignore-case"); int cic = 1; if (cic_var && STREQ (cic_var, "off")) cic = 0; int matches = cic ? STRCASEEQLEN (word->name, text, len) : STREQLEN (word->name, text, len); if (matches) { if (word->is_dir) rl_completion_append_character = '/'; return strdup (word->name); } } #endif /* HAVE_LIBREADLINE */ return NULL; }
static int scan (guestfs_h *g, const char *prefix, FILE *fp) { size_t i, j; size_t alignment; uint64_t start; int err; CLEANUP_FREE_STRING_LIST char **devices = guestfs_list_devices (g); if (devices == NULL) return -1; for (i = 0; devices[i] != NULL; ++i) { CLEANUP_FREE char *name = NULL; CLEANUP_FREE_PARTITION_LIST struct guestfs_partition_list *parts = guestfs_part_list (g, devices[i]); if (parts == NULL) return -1; /* Canonicalize the name of the device for printing. */ name = guestfs_canonical_device_name (g, devices[i]); if (name == NULL) return -1; for (j = 0; j < parts->len; ++j) { /* Start offset of the partition in bytes. */ start = parts->val[j].part_start; if (!quiet) { if (prefix) fprintf (fp, "%s:", prefix); fprintf (fp, "%s%d %12" PRIu64 " ", name, (int) parts->val[j].part_num, start); } /* What's the alignment? */ if (start == 0) /* Probably not possible, but anyway. */ alignment = 64; else for (alignment = 0; (start & 1) == 0; alignment++, start /= 2) ; if (!quiet) { if (alignment < 10) fprintf (fp, "%12" PRIu64 " ", UINT64_C(1) << alignment); else if (alignment < 64) fprintf (fp, "%12" PRIu64 "K ", UINT64_C(1) << (alignment - 10)); else fprintf (fp, "- "); } err = pthread_mutex_lock (&worst_alignment_mutex); assert (err == 0); if (alignment < worst_alignment) worst_alignment = alignment; err = pthread_mutex_unlock (&worst_alignment_mutex); assert (err == 0); if (alignment < 12) { /* Bad in general: < 4K alignment */ if (!quiet) fprintf (fp, "bad (%s)\n", _("alignment < 4K")); } else if (alignment < 16) { /* Bad on NetApps: < 64K alignment */ if (!quiet) fprintf (fp, "bad (%s)\n", _("alignment < 64K")); } else { if (!quiet) fprintf (fp, "ok\n"); } } } return 0; }
/* Returns 0 on success, 1 if we need to retry. */ static int do_format (void) { size_t i; CLEANUP_FREE_STRING_LIST char **devices = guestfs_list_devices (g); if (devices == NULL) exit (EXIT_FAILURE); /* Erase the disks. */ if (!wipe) { for (i = 0; devices[i] != NULL; ++i) { /* erase the filesystem signatures on each device */ if (have_wipefs && guestfs_wipefs (g, devices[i]) == -1) exit (EXIT_FAILURE); /* Then erase the partition table on each device. */ if (guestfs_zero (g, devices[i]) == -1) exit (EXIT_FAILURE); } } else /* wipe */ { for (i = 0; devices[i] != NULL; ++i) { if (guestfs_zero_device (g, devices[i]) == -1) exit (EXIT_FAILURE); } } /* Send TRIM/UNMAP to all block devices, to give back the space to * the host. However don't fail if this doesn't work. */ guestfs_push_error_handler (g, NULL, NULL); for (i = 0; devices[i] != NULL; ++i) guestfs_blkdiscard (g, devices[i]); guestfs_pop_error_handler (g); if (do_rescan (devices)) return 1; /* which means, reopen the handle and retry */ /* Format each disk. */ for (i = 0; devices[i] != NULL; ++i) { char *dev = devices[i]; int free_dev = 0; if (partition) { const char *ptype = partition; int64_t dev_size; /* If partition has the magic value "DEFAULT", choose either MBR or GPT.*/ if (STREQ (partition, "DEFAULT")) { dev_size = guestfs_blockdev_getsize64 (g, devices[i]); if (dev_size == -1) exit (EXIT_FAILURE); ptype = dev_size < INT64_C(2)*1024*1024*1024*1024 ? "mbr" : "gpt"; } if (guestfs_part_disk (g, devices[i], ptype) == -1) exit (EXIT_FAILURE); if (asprintf (&dev, "%s1", devices[i]) == -1) { perror ("asprintf"); exit (EXIT_FAILURE); } free_dev = 1; /* Set the partition type byte appropriately, otherwise Windows * won't see the filesystem (RHBZ#1000428). */ if (STREQ (ptype, "mbr") || STREQ (ptype, "msdos")) { int mbr_id = 0; if (vg && lv) mbr_id = 0x8e; else if (filesystem) { if (STREQ (filesystem, "msdos")) mbr_id = 0x01; else if (STREQ (filesystem, "fat") || STREQ (filesystem, "vfat")) mbr_id = 0x0b; else if (STREQ (filesystem, "ntfs")) mbr_id = 0x07; else if (STRPREFIX (filesystem, "ext")) mbr_id = 0x83; else if (STREQ (filesystem, "minix")) mbr_id = 0x81; } if (mbr_id > 0) guestfs_part_set_mbr_id (g, devices[i], 1, mbr_id); } } if (vg && lv) { char *devs[2] = { dev, NULL }; if (guestfs_pvcreate (g, dev) == -1) exit (EXIT_FAILURE); if (guestfs_vgcreate (g, vg, devs) == -1) exit (EXIT_FAILURE); if (guestfs_lvcreate_free (g, lv, vg, 100) == -1) exit (EXIT_FAILURE); if (free_dev) free (dev); if (asprintf (&dev, "/dev/%s/%s", vg, lv) == -1) { perror ("asprintf"); exit (EXIT_FAILURE); } free_dev = 1; } if (filesystem) { if (guestfs_mkfs_opts (g, filesystem, dev, -1) == -1) exit (EXIT_FAILURE); if (label) { if (guestfs_set_label (g, dev, label) == -1) exit (EXIT_FAILURE); } } if (free_dev) free (dev); } if (guestfs_sync (g) == -1) exit (EXIT_FAILURE); return 0; }