/* Emulate this by calling sync. */ static int fg_fsync(const char *path, int isdatasync, struct fuse_file_info *fi) { TRACE_CALL ("%s, %d", path, isdatasync); int r; r = guestfs_sync (g); if (r == -1) return error (); return 0; }
/* Emulate this by calling sync. */ static int mount_local_fsync (const char *path, int isdatasync, struct fuse_file_info *fi) { int r; DECL_G (); DEBUG_CALL ("%s, %d", path, isdatasync); r = guestfs_sync (g); if (r == -1) RETURN_ERRNO; return 0; }
int main (int argc, char *argv[]) { /* Set global program name that is not polluted with libtool artifacts. */ set_program_name (argv[0]); setlocale (LC_ALL, ""); bindtextdomain (PACKAGE, LOCALEBASEDIR); textdomain (PACKAGE); /* We use random(3) below. */ srandom (time (NULL)); enum { HELP_OPTION = CHAR_MAX + 1 }; static const char *options = "a:b:c:d:e:vVx"; static const struct option long_options[] = { { "add", 1, 0, 'a' }, { "backup", 1, 0, 'b' }, { "connect", 1, 0, 'c' }, { "domain", 1, 0, 'd' }, { "echo-keys", 0, 0, 0 }, { "expr", 1, 0, 'e' }, { "format", 2, 0, 0 }, { "help", 0, 0, HELP_OPTION }, { "keys-from-stdin", 0, 0, 0 }, { "verbose", 0, 0, 'v' }, { "version", 0, 0, 'V' }, { 0, 0, 0, 0 } }; struct drv *drvs = NULL; struct drv *drv; const char *format = NULL; int c; int option_index; char *root, **roots; g = guestfs_create (); if (g == NULL) { fprintf (stderr, _("guestfs_create: failed to create handle\n")); exit (EXIT_FAILURE); } argv[0] = bad_cast (program_name); for (;;) { c = getopt_long (argc, argv, options, long_options, &option_index); if (c == -1) break; switch (c) { case 0: /* options which are long only */ if (STREQ (long_options[option_index].name, "keys-from-stdin")) { keys_from_stdin = 1; } else if (STREQ (long_options[option_index].name, "echo-keys")) { echo_keys = 1; } else if (STREQ (long_options[option_index].name, "format")) { if (!optarg || STREQ (optarg, "")) format = NULL; else format = optarg; } else { fprintf (stderr, _("%s: unknown long option: %s (%d)\n"), program_name, long_options[option_index].name, option_index); exit (EXIT_FAILURE); } break; case 'a': OPTION_a; break; case 'b': if (backup_extension) { fprintf (stderr, _("%s: -b option given multiple times\n"), program_name); exit (EXIT_FAILURE); } backup_extension = optarg; break; case 'c': OPTION_c; break; case 'd': OPTION_d; break; case 'e': if (perl_expr) { fprintf (stderr, _("%s: -e option given multiple times\n"), program_name); exit (EXIT_FAILURE); } perl_expr = optarg; break; case 'h': usage (EXIT_SUCCESS); case 'v': OPTION_v; break; case 'V': OPTION_V; break; case 'x': OPTION_x; break; case HELP_OPTION: usage (EXIT_SUCCESS); default: usage (EXIT_FAILURE); } } /* Old-style syntax? There were no -a or -d options in the old * virt-edit which is how we detect this. */ if (drvs == NULL) { /* argc - 1 because last parameter is the single filename. */ while (optind < argc - 1) { if (strchr (argv[optind], '/') || access (argv[optind], F_OK) == 0) { /* simulate -a option */ drv = malloc (sizeof (struct drv)); if (!drv) { perror ("malloc"); exit (EXIT_FAILURE); } drv->type = drv_a; drv->a.filename = argv[optind]; drv->a.format = NULL; drv->next = drvs; drvs = drv; } else { /* simulate -d option */ drv = malloc (sizeof (struct drv)); if (!drv) { perror ("malloc"); exit (EXIT_FAILURE); } drv->type = drv_d; drv->d.guest = argv[optind]; drv->next = drvs; drvs = drv; } optind++; } } /* These are really constants, but they have to be variables for the * options parsing code. Assert here that they have known-good * values. */ assert (read_only == 0); assert (inspector == 1); assert (live == 0); /* User must specify at least one filename on the command line. */ if (optind >= argc || argc - optind < 1) usage (EXIT_FAILURE); /* User must have specified some drives. */ if (drvs == NULL) usage (EXIT_FAILURE); /* Add drives. */ add_drives (drvs, 'a'); if (guestfs_launch (g) == -1) exit (EXIT_FAILURE); inspect_mount (); /* Free up data structures, no longer needed after this point. */ free_drives (drvs); /* Get root mountpoint. */ roots = guestfs_inspect_get_roots (g); if (!roots) exit (EXIT_FAILURE); /* see fish/inspect.c:inspect_mount */ assert (roots[0] != NULL && roots[1] == NULL); root = roots[0]; free (roots); while (optind < argc) { edit (argv[optind], root); optind++; } free (root); /* Cleanly unmount the disks after editing. */ if (guestfs_umount_all (g) == -1 || guestfs_sync (g) == -1) exit (EXIT_FAILURE); guestfs_close (g); exit (EXIT_SUCCESS); }
/* 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; }
/* 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; }