summaryrefslogtreecommitdiffstats
path: root/daemon
diff options
context:
space:
mode:
authorRichard W.M. Jones <rjones@redhat.com>2012-04-25 16:35:12 +0100
committerRichard W.M. Jones <rjones@redhat.com>2012-04-25 17:32:30 +0100
commit87ea7a04094d5ed40f3f047ff2b7a613d4d530d4 (patch)
tree458b3713c313d124c37b8de11e45d0b081f3fde6 /daemon
parent3cc9703f901e85a589692b9d0bf5ef7cbf72ed73 (diff)
downloadlibguestfs-87ea7a04094d5ed40f3f047ff2b7a613d4d530d4.tar.gz
libguestfs-87ea7a04094d5ed40f3f047ff2b7a613d4d530d4.tar.xz
libguestfs-87ea7a04094d5ed40f3f047ff2b7a613d4d530d4.zip
New btrfs APIs.
Bind the easy parts of the 'btrfs' program. The new APIs are: btrfs-device-add: add devices to a btrfs filesystem btrfs-device-delete: remove devices from a btrfs filesystem btrfs-filesystem-sync: sync a btrfs filesystem btrfs-filesystem-balance: balance a btrfs filesystem btrfs-subvolume-create: create a btrfs snapshot btrfs-subvolume-delete: delete a btrfs snapshot btrfs-subvolume-list: list btrfs snapshots and subvolumes btrfs-subvolume-set-default: set default btrfs subvolume btrfs-subvolume-snapshot: create a writable btrfs snapshot
Diffstat (limited to 'daemon')
-rw-r--r--daemon/btrfs.c396
1 files changed, 396 insertions, 0 deletions
diff --git a/daemon/btrfs.c b/daemon/btrfs.c
index 60c863a4..8569173e 100644
--- a/daemon/btrfs.c
+++ b/daemon/btrfs.c
@@ -202,3 +202,399 @@ do_mkfs_btrfs (char *const *devices,
free (err);
return 0;
}
+
+int
+do_btrfs_subvolume_snapshot (const char *source, const char *dest)
+{
+ const size_t MAX_ARGS = 64;
+ const char *argv[MAX_ARGS];
+ size_t i = 0;
+ char *source_buf, *dest_buf;
+ char *err;
+ int r;
+
+ source_buf = sysroot_path (source);
+ if (source_buf == NULL) {
+ reply_with_perror ("malloc");
+ return -1;
+ }
+ dest_buf = sysroot_path (dest);
+ if (dest_buf == NULL) {
+ reply_with_perror ("malloc");
+ free (source_buf);
+ return -1;
+ }
+
+ ADD_ARG (argv, i, "btrfs");
+ ADD_ARG (argv, i, "subvolume");
+ ADD_ARG (argv, i, "snapshot");
+ ADD_ARG (argv, i, source_buf);
+ ADD_ARG (argv, i, dest_buf);
+ ADD_ARG (argv, i, NULL);
+
+ r = commandv (NULL, &err, argv);
+ free (source_buf);
+ free (dest_buf);
+ if (r == -1) {
+ reply_with_error ("%s: %s: %s", source, dest, err);
+ free (err);
+ return -1;
+ }
+ free (err);
+
+ return 0;
+}
+
+int
+do_btrfs_subvolume_delete (const char *subvolume)
+{
+ const size_t MAX_ARGS = 64;
+ const char *argv[MAX_ARGS];
+ size_t i = 0;
+ char *subvolume_buf;
+ char *err;
+ int r;
+
+ subvolume_buf = sysroot_path (subvolume);
+ if (subvolume_buf == NULL) {
+ reply_with_perror ("malloc");
+ return -1;
+ }
+
+ ADD_ARG (argv, i, "btrfs");
+ ADD_ARG (argv, i, "subvolume");
+ ADD_ARG (argv, i, "delete");
+ ADD_ARG (argv, i, subvolume_buf);
+ ADD_ARG (argv, i, NULL);
+
+ r = commandv (NULL, &err, argv);
+ free (subvolume_buf);
+ if (r == -1) {
+ reply_with_error ("%s: %s", subvolume, err);
+ free (err);
+ return -1;
+ }
+ free (err);
+
+ return 0;
+}
+
+int
+do_btrfs_subvolume_create (const char *dest)
+{
+ const size_t MAX_ARGS = 64;
+ const char *argv[MAX_ARGS];
+ size_t i = 0;
+ char *dest_buf;
+ char *err;
+ int r;
+
+ dest_buf = sysroot_path (dest);
+ if (dest_buf == NULL) {
+ reply_with_perror ("malloc");
+ return -1;
+ }
+
+ ADD_ARG (argv, i, "btrfs");
+ ADD_ARG (argv, i, "subvolume");
+ ADD_ARG (argv, i, "create");
+ ADD_ARG (argv, i, dest_buf);
+ ADD_ARG (argv, i, NULL);
+
+ r = commandv (NULL, &err, argv);
+ free (dest_buf);
+ if (r == -1) {
+ reply_with_error ("%s: %s", dest, err);
+ free (err);
+ return -1;
+ }
+ free (err);
+
+ return 0;
+}
+
+guestfs_int_btrfssubvolume_list *
+do_btrfs_subvolume_list (const char *fs)
+{
+ const size_t MAX_ARGS = 64;
+ guestfs_int_btrfssubvolume_list *ret;
+ char *fs_buf;
+ const char *argv[MAX_ARGS];
+ size_t i = 0;
+ char *out, *err, **lines, *pos;
+ size_t nr_subvolumes;
+ int r;
+
+ fs_buf = sysroot_path (fs);
+ if (fs_buf == NULL) {
+ reply_with_perror ("malloc");
+ return NULL;
+ }
+
+ ADD_ARG (argv, i, "btrfs");
+ ADD_ARG (argv, i, "subvolume");
+ ADD_ARG (argv, i, "list");
+ ADD_ARG (argv, i, fs_buf);
+ ADD_ARG (argv, i, NULL);
+
+ r = commandv (&out, &err, argv);
+ free (fs_buf);
+ if (r == -1) {
+ reply_with_error ("%s: %s", fs, err);
+ free (err);
+ return NULL;
+ }
+ free (err);
+
+ lines = split_lines (out);
+ free (out);
+ if (!lines)
+ return NULL;
+
+ /* Output is:
+ *
+ * ID 256 top level 5 path test1
+ * ID 257 top level 5 path dir/test2
+ * ID 258 top level 5 path test3
+ *
+ * "ID <n>" is the subvolume ID. "top level <n>" is the top level
+ * subvolume ID. "path <str>" is the subvolume path, relative to
+ * the top of the filesystem.
+ */
+ nr_subvolumes = count_strings (lines);
+
+ ret = malloc (sizeof *ret);
+ if (!ret) {
+ reply_with_perror ("malloc");
+ free_stringslen (lines, nr_subvolumes);
+ return NULL;
+ }
+ ret->guestfs_int_btrfssubvolume_list_len = nr_subvolumes;
+ ret->guestfs_int_btrfssubvolume_list_val =
+ calloc (nr_subvolumes, sizeof (struct guestfs_int_btrfssubvolume));
+ if (ret->guestfs_int_btrfssubvolume_list_val == NULL) {
+ reply_with_perror ("malloc");
+ free (ret);
+ free_stringslen (lines, nr_subvolumes);
+ return NULL;
+ }
+
+ for (i = 0; i < nr_subvolumes; ++i) {
+ /* To avoid allocations, reuse the 'line' buffer to store the
+ * path. Thus we don't need to free 'line', since it will be
+ * freed by the calling (XDR) code.
+ */
+ char *line = lines[i];
+
+ if (sscanf (line, "ID %" SCNu64 " top level %" SCNu64 " path ",
+ &ret->guestfs_int_btrfssubvolume_list_val[i].btrfssubvolume_id,
+ &ret->guestfs_int_btrfssubvolume_list_val[i].btrfssubvolume_top_level_id) != 2) {
+ unexpected_output:
+ reply_with_error ("unexpected output from 'btrfs subvolume list' command: %s", line);
+ free_stringslen (lines, nr_subvolumes);
+ free (ret->guestfs_int_btrfssubvolume_list_val);
+ free (ret);
+ return NULL;
+ }
+
+ pos = strstr (line, " path ");
+ if (pos == NULL)
+ goto unexpected_output;
+ pos += 6;
+
+ memmove (line, pos, strlen (pos) + 1);
+ ret->guestfs_int_btrfssubvolume_list_val[i].btrfssubvolume_path = line;
+ }
+
+ return ret;
+}
+
+int
+do_btrfs_subvolume_set_default (int64_t id, const char *fs)
+{
+ const size_t MAX_ARGS = 64;
+ const char *argv[MAX_ARGS];
+ size_t i = 0;
+ char *fs_buf;
+ char buf[64];
+ char *err;
+ int r;
+
+ snprintf (buf, sizeof buf, "%" PRIi64, id);
+
+ fs_buf = sysroot_path (fs);
+ if (fs_buf == NULL) {
+ reply_with_perror ("malloc");
+ return -1;
+ }
+
+ ADD_ARG (argv, i, "btrfs");
+ ADD_ARG (argv, i, "subvolume");
+ ADD_ARG (argv, i, "set-default");
+ ADD_ARG (argv, i, buf);
+ ADD_ARG (argv, i, fs_buf);
+ ADD_ARG (argv, i, NULL);
+
+ r = commandv (NULL, &err, argv);
+ free (fs_buf);
+ if (r == -1) {
+ reply_with_error ("%s: %s", fs, err);
+ free (err);
+ return -1;
+ }
+ free (err);
+
+ return 0;
+}
+
+int
+do_btrfs_filesystem_sync (const char *fs)
+{
+ const size_t MAX_ARGS = 64;
+ const char *argv[MAX_ARGS];
+ size_t i = 0;
+ char *fs_buf;
+ char *err;
+ int r;
+
+ fs_buf = sysroot_path (fs);
+ if (fs_buf == NULL) {
+ reply_with_perror ("malloc");
+ return -1;
+ }
+
+ ADD_ARG (argv, i, "btrfs");
+ ADD_ARG (argv, i, "filesystem");
+ ADD_ARG (argv, i, "sync");
+ ADD_ARG (argv, i, fs_buf);
+ ADD_ARG (argv, i, NULL);
+
+ r = commandv (NULL, &err, argv);
+ free (fs_buf);
+ if (r == -1) {
+ reply_with_error ("%s: %s", fs, err);
+ free (err);
+ return -1;
+ }
+ free (err);
+
+ return 0;
+}
+
+int
+do_btrfs_filesystem_balance (const char *fs)
+{
+ const size_t MAX_ARGS = 64;
+ const char *argv[MAX_ARGS];
+ size_t i = 0;
+ char *fs_buf;
+ char *err;
+ int r;
+
+ fs_buf = sysroot_path (fs);
+ if (fs_buf == NULL) {
+ reply_with_perror ("malloc");
+ return -1;
+ }
+
+ ADD_ARG (argv, i, "btrfs");
+ ADD_ARG (argv, i, "filesystem");
+ ADD_ARG (argv, i, "balance");
+ ADD_ARG (argv, i, fs_buf);
+ ADD_ARG (argv, i, NULL);
+
+ r = commandv (NULL, &err, argv);
+ free (fs_buf);
+ if (r == -1) {
+ reply_with_error ("%s: %s", fs, err);
+ free (err);
+ return -1;
+ }
+ free (err);
+
+ return 0;
+}
+
+int
+do_btrfs_device_add (char *const *devices, const char *fs)
+{
+ size_t nr_devices = count_strings (devices);
+
+ if (nr_devices == 0)
+ return 0;
+
+ size_t MAX_ARGS = nr_devices + 8;
+ const char *argv[MAX_ARGS];
+ size_t i = 0, j;
+ char *fs_buf;
+ char *err;
+ int r;
+
+ fs_buf = sysroot_path (fs);
+ if (fs_buf == NULL) {
+ reply_with_perror ("malloc");
+ return -1;
+ }
+
+ ADD_ARG (argv, i, "btrfs");
+ ADD_ARG (argv, i, "device");
+ ADD_ARG (argv, i, "add");
+
+ for (j = 0; j < nr_devices; ++j)
+ ADD_ARG (argv, i, devices[j]);
+
+ ADD_ARG (argv, i, fs_buf);
+ ADD_ARG (argv, i, NULL);
+
+ r = commandv (NULL, &err, argv);
+ free (fs_buf);
+ if (r == -1) {
+ reply_with_error ("%s: %s", fs, err);
+ free (err);
+ return -1;
+ }
+ free (err);
+
+ return 0;
+}
+
+int
+do_btrfs_device_delete (char *const *devices, const char *fs)
+{
+ size_t nr_devices = count_strings (devices);
+
+ if (nr_devices == 0)
+ return 0;
+
+ size_t MAX_ARGS = nr_devices + 8;
+ const char *argv[MAX_ARGS];
+ size_t i = 0, j;
+ char *fs_buf;
+ char *err;
+ int r;
+
+ fs_buf = sysroot_path (fs);
+ if (fs_buf == NULL) {
+ reply_with_perror ("malloc");
+ return -1;
+ }
+
+ ADD_ARG (argv, i, "btrfs");
+ ADD_ARG (argv, i, "device");
+ ADD_ARG (argv, i, "delete");
+ for (j = 0; j < nr_devices; ++j)
+ ADD_ARG (argv, i, devices[j]);
+ ADD_ARG (argv, i, fs);
+ ADD_ARG (argv, i, NULL);
+
+ r = commandv (NULL, &err, argv);
+ free (fs_buf);
+ if (r == -1) {
+ reply_with_error ("%s: %s", fs, err);
+ free (err);
+ return -1;
+ }
+ free (err);
+
+ return 0;
+}