From 8e570870f577ff0c3db074f88924633b559af5d4 Mon Sep 17 00:00:00 2001 From: Richard Jones Date: Mon, 6 Apr 2009 12:55:26 +0100 Subject: [PATCH] Implement list-devices and list-partitions. --- daemon/Makefile.am | 1 + daemon/actions.h | 8 +- daemon/daemon.h | 2 + daemon/devsparts.c | 133 ++++++++++++++++++ daemon/guestfsd.c | 24 ++++ daemon/ls.c | 10 +- daemon/stubs.c | 144 ++++++++++++------- fish/cmds.c | 130 ++++++++++++------ guestfs-actions.pod | 41 +++++- src/generator.ml | 153 +++++++++++++++------ src/guestfs-actions.c | 364 ++++++++++++++++++++++++++++++++++--------------- src/guestfs-actions.h | 8 +- src/guestfs_protocol.c | 34 ++++- src/guestfs_protocol.h | 52 +++++-- src/guestfs_protocol.x | 38 ++++-- 15 files changed, 842 insertions(+), 300 deletions(-) create mode 100644 daemon/devsparts.c diff --git a/daemon/Makefile.am b/daemon/Makefile.am index 76e75c6..5faa652 100644 --- a/daemon/Makefile.am +++ b/daemon/Makefile.am @@ -21,6 +21,7 @@ noinst_PROGRAMS = guestfsd guestfsd_SOURCES = \ actions.h \ daemon.h \ + devsparts.c \ file.c \ guestfsd.c \ ls.c \ diff --git a/daemon/actions.h b/daemon/actions.h index c4b9b15..58b8a24 100644 --- a/daemon/actions.h +++ b/daemon/actions.h @@ -19,9 +19,11 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -extern char *do_cat (const char *path); -extern char *do_ll (const char *directory); -extern char **do_ls (const char *directory); extern int do_mount (const char *device, const char *mountpoint); extern int do_sync (); extern int do_touch (const char *path); +extern char *do_cat (const char *path); +extern char *do_ll (const char *directory); +extern char **do_ls (const char *directory); +extern char **do_list_devices (); +extern char **do_list_partitions (); diff --git a/daemon/daemon.h b/daemon/daemon.h index 3740595..60e1982 100644 --- a/daemon/daemon.h +++ b/daemon/daemon.h @@ -29,7 +29,9 @@ extern void xread (int sock, void *buf, size_t len); extern int add_string (char ***argv, int *size, int *alloc, const char *str); extern int count_strings (char **argv); +extern void sort_strings (char **argv, int len); extern void free_strings (char **argv); +extern void free_stringslen (char **argv, int len); extern int command (char **stdoutput, char **stderror, const char *name, ...); diff --git a/daemon/devsparts.c b/daemon/devsparts.c new file mode 100644 index 0000000..b0d7956 --- /dev/null +++ b/daemon/devsparts.c @@ -0,0 +1,133 @@ +/* libguestfs - the guestfsd daemon + * Copyright (C) 2009 Red Hat Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "daemon.h" +#include "actions.h" + +char ** +do_list_devices (void) +{ + char **r = NULL; + int size = 0, alloc = 0; + DIR *dir; + struct dirent *d; + char buf[256]; + + dir = opendir ("/sys/block"); + if (!dir) { + reply_with_perror ("opendir: /sys/block"); + return NULL; + } + + while ((d = readdir (dir)) != NULL) { + if (strncmp (d->d_name, "sd", 2) == 0) { + snprintf (buf, sizeof buf, "/dev/%s", d->d_name); + if (add_string (&r, &size, &alloc, buf) == -1) { + closedir (dir); + return NULL; + } + } + } + + if (add_string (&r, &size, &alloc, NULL) == -1) { + closedir (dir); + return NULL; + } + + if (closedir (dir) == -1) { + reply_with_perror ("closedir: /sys/block"); + free_strings (r); + return NULL; + } + + sort_strings (r, size-1); + return r; +} + +char ** +do_list_partitions (void) +{ + char **r = NULL; + int size = 0, alloc = 0; + DIR *dir, *dir2; + struct dirent *d; + char buf[256], devname[256]; + + dir = opendir ("/sys/block"); + if (!dir) { + reply_with_perror ("opendir: /sys/block"); + return NULL; + } + + while ((d = readdir (dir)) != NULL) { + if (strncmp (d->d_name, "sd", 2) == 0) { + strncpy (devname, d->d_name, sizeof devname); + devname[sizeof devname - 1] = '\0'; + + snprintf (buf, sizeof buf, "/sys/block/%s", devname); + + dir2 = opendir (buf); + if (!dir2) { + reply_with_perror ("opendir: %s", buf); + free_stringslen (r, size); + return NULL; + } + while ((d = readdir (dir2)) != NULL) { + if (strncmp (d->d_name, devname, strlen (devname)) == 0) { + snprintf (buf, sizeof buf, "/dev/%s", d->d_name); + + if (add_string (&r, &size, &alloc, buf) == -1) { + closedir (dir2); + closedir (dir); + return NULL; + } + } + } + + if (closedir (dir2) == -1) { + reply_with_perror ("closedir: /sys/block/%s", devname); + free_stringslen (r, size); + return NULL; + } + } + } + + if (add_string (&r, &size, &alloc, NULL) == -1) { + closedir (dir); + return NULL; + } + + if (closedir (dir) == -1) { + reply_with_perror ("closedir: /sys/block"); + free_strings (r); + return NULL; + } + + sort_strings (r, size-1); + return r; +} diff --git a/daemon/guestfsd.c b/daemon/guestfsd.c index 6730c1d..a243c0b 100644 --- a/daemon/guestfsd.c +++ b/daemon/guestfsd.c @@ -272,6 +272,20 @@ count_strings (char **argv) return argc; } +static int +compare (const void *vp1, const void *vp2) +{ + char * const *p1 = (char * const *) vp1; + char * const *p2 = (char * const *) vp2; + return strcmp (*p1, *p2); +} + +void +sort_strings (char **argv, int len) +{ + qsort (argv, len, sizeof (char *), compare); +} + void free_strings (char **argv) { @@ -282,6 +296,16 @@ free_strings (char **argv) free (argv); } +void +free_stringslen (char **argv, int len) +{ + int i; + + for (i = 0; i < len; ++i) + free (argv[i]); + free (argv); +} + /* This is a more sane version of 'system(3)' for running external * commands. It uses fork/execvp, so we don't need to worry about * quoting of parameters, and it allows us to capture any error diff --git a/daemon/ls.c b/daemon/ls.c index 05e2cc7..261bc96 100644 --- a/daemon/ls.c +++ b/daemon/ls.c @@ -29,14 +29,6 @@ #include "daemon.h" #include "actions.h" -static int -compare (const void *vp1, const void *vp2) -{ - char * const *p1 = (char * const *) vp1; - char * const *p2 = (char * const *) vp2; - return strcmp (*p1, *p2); -} - char ** do_ls (const char *path) { @@ -78,7 +70,7 @@ do_ls (const char *path) return NULL; } - qsort (r, size-1, sizeof (char *), compare); + sort_strings (r, size-1); return r; } diff --git a/daemon/stubs.c b/daemon/stubs.c index 4eccfb5..faece82 100644 --- a/daemon/stubs.c +++ b/daemon/stubs.c @@ -25,6 +25,64 @@ #include "../src/guestfs_protocol.h" #include "actions.h" +static void mount_stub (XDR *xdr_in) +{ + int r; + struct guestfs_mount_args args; + const char *device; + const char *mountpoint; + + memset (&args, 0, sizeof args); + + if (!xdr_guestfs_mount_args (xdr_in, &args)) { + reply_with_error ("mount: daemon failed to decode procedure arguments"); + return; + } + device = args.device; + mountpoint = args.mountpoint; + + r = do_mount (device, mountpoint); + if (r == -1) + /* do_mount has already called reply_with_error, so just return */ + return; + + reply (NULL, NULL); +} + +static void sync_stub (XDR *xdr_in) +{ + int r; + + r = do_sync (); + if (r == -1) + /* do_sync has already called reply_with_error, so just return */ + return; + + reply (NULL, NULL); +} + +static void touch_stub (XDR *xdr_in) +{ + int r; + struct guestfs_touch_args args; + const char *path; + + memset (&args, 0, sizeof args); + + if (!xdr_guestfs_touch_args (xdr_in, &args)) { + reply_with_error ("touch: daemon failed to decode procedure arguments"); + return; + } + path = args.path; + + r = do_touch (path); + if (r == -1) + /* do_touch has already called reply_with_error, so just return */ + return; + + reply (NULL, NULL); +} + static void cat_stub (XDR *xdr_in) { char *r; @@ -101,67 +159,50 @@ static void ls_stub (XDR *xdr_in) free_strings (r); } -static void mount_stub (XDR *xdr_in) -{ - int r; - struct guestfs_mount_args args; - const char *device; - const char *mountpoint; - - memset (&args, 0, sizeof args); - - if (!xdr_guestfs_mount_args (xdr_in, &args)) { - reply_with_error ("mount: daemon failed to decode procedure arguments"); - return; - } - device = args.device; - mountpoint = args.mountpoint; - - r = do_mount (device, mountpoint); - if (r == -1) - /* do_mount has already called reply_with_error, so just return */ - return; - - reply (NULL, NULL); -} - -static void sync_stub (XDR *xdr_in) +static void list_devices_stub (XDR *xdr_in) { - int r; + char **r; - r = do_sync (); - if (r == -1) - /* do_sync has already called reply_with_error, so just return */ + r = do_list_devices (); + if (r == NULL) + /* do_list_devices has already called reply_with_error, so just return */ return; - reply (NULL, NULL); + struct guestfs_list_devices_ret ret; + ret.devices.devices_len = count_strings (r); + ret.devices.devices_val = r; + reply ((xdrproc_t) &xdr_guestfs_list_devices_ret, (char *) &ret); + free_strings (r); } -static void touch_stub (XDR *xdr_in) +static void list_partitions_stub (XDR *xdr_in) { - int r; - struct guestfs_touch_args args; - const char *path; - - memset (&args, 0, sizeof args); - - if (!xdr_guestfs_touch_args (xdr_in, &args)) { - reply_with_error ("touch: daemon failed to decode procedure arguments"); - return; - } - path = args.path; + char **r; - r = do_touch (path); - if (r == -1) - /* do_touch has already called reply_with_error, so just return */ + r = do_list_partitions (); + if (r == NULL) + /* do_list_partitions has already called reply_with_error, so just return */ return; - reply (NULL, NULL); + struct guestfs_list_partitions_ret ret; + ret.partitions.partitions_len = count_strings (r); + ret.partitions.partitions_val = r; + reply ((xdrproc_t) &xdr_guestfs_list_partitions_ret, (char *) &ret); + free_strings (r); } void dispatch_incoming_message (XDR *xdr_in) { switch (proc_nr) { + case GUESTFS_PROC_MOUNT: + mount_stub (xdr_in); + break; + case GUESTFS_PROC_SYNC: + sync_stub (xdr_in); + break; + case GUESTFS_PROC_TOUCH: + touch_stub (xdr_in); + break; case GUESTFS_PROC_CAT: cat_stub (xdr_in); break; @@ -171,14 +212,11 @@ void dispatch_incoming_message (XDR *xdr_in) case GUESTFS_PROC_LS: ls_stub (xdr_in); break; - case GUESTFS_PROC_MOUNT: - mount_stub (xdr_in); + case GUESTFS_PROC_LIST_DEVICES: + list_devices_stub (xdr_in); break; - case GUESTFS_PROC_SYNC: - sync_stub (xdr_in); - break; - case GUESTFS_PROC_TOUCH: - touch_stub (xdr_in); + case GUESTFS_PROC_LIST_PARTITIONS: + list_partitions_stub (xdr_in); break; default: reply_with_error ("dispatch_incoming_message: unknown procedure number %d", proc_nr); diff --git a/fish/cmds.c b/fish/cmds.c index 3116c94..28dd956 100644 --- a/fish/cmds.c +++ b/fish/cmds.c @@ -30,6 +30,8 @@ void list_commands (void) printf (" %-16s %s\n", "Command", "Description"); list_builtin_commands (); printf ("%-20s %s\n", "cat", "list the contents of a file"); + printf ("%-20s %s\n", "list-devices", "list the block devices"); + printf ("%-20s %s\n", "list-partitions", "list the partitions"); printf ("%-20s %s\n", "ll", "list the files in a directory (long format)"); printf ("%-20s %s\n", "ls", "list the files in a directory"); printf ("%-20s %s\n", "mount", "mount a guest disk at a position in the filesystem"); @@ -40,8 +42,17 @@ void list_commands (void) void display_command (const char *cmd) { + if (strcasecmp (cmd, "mount") == 0) + pod2text ("mount - mount a guest disk at a position in the filesystem", " mount \n\nMount a guest disk at a position in the filesystem. Block devices\nare named C, C and so on, as they were added to\nthe guest. If those block devices contain partitions, they will have\nthe usual names (eg. C). Also LVM C-style\nnames can be used.\n\nThe rules are the same as for L: A filesystem must\nfirst be mounted on C before others can be mounted. Other\nfilesystems can only be mounted on directories which already\nexist.\n\nThe mounted filesystem is writable, if we have sufficient permissions\non the underlying device.\n\nThe filesystem options C and C are set with this\ncall, in order to improve reliability."); + else + if (strcasecmp (cmd, "sync") == 0) + pod2text ("sync - sync disks, writes are flushed through to the disk image", " sync\n\nThis syncs the disk, so that any writes are flushed through to the\nunderlying disk image.\n\nYou should always call this if you have modified a disk image, before\ncalling C."); + else + if (strcasecmp (cmd, "touch") == 0) + pod2text ("touch - update file timestamps or create a new file", " touch \n\nTouch acts like the L command. It can be used to\nupdate the timestamps on a file, or, if the file does not exist,\nto create a new zero-length file."); + else if (strcasecmp (cmd, "cat") == 0) - pod2text ("cat - list the contents of a file", " cat \n\nReturn the contents of the file named C.\n\nNote that this function cannot correctly handle binary files\n(specifically, files containing C<\\0> character which is treated\nas end of string). For those you need to use the C\nfunction which has a more complex interface.\n\nBecause of the message protocol, there is a transfer limit \nof somewhere between 2MB and 4MB. To transfer large files you should use\nFTP."); + pod2text ("cat - list the contents of a file", " cat \n\nReturn the contents of the file named C.\n\nNote that this function cannot correctly handle binary files\n(specifically, files containing C<\\0> character which is treated\nas end of string). For those you need to use the C\nfunction which has a more complex interface.\n\nBecause of the message protocol, there is a transfer limit \nof somewhere between 2MB and 4MB. To transfer large files you should use\nFTP."); else if (strcasecmp (cmd, "ll") == 0) pod2text ("ll - list the files in a directory (long format)", " ll \n\nList the files in C (relative to the root directory,\nthere is no cwd) in the format of 'ls -la'.\n\nThis command is mostly useful for interactive sessions. It\nis I intended that you try to parse the output string."); @@ -49,18 +60,57 @@ void display_command (const char *cmd) if (strcasecmp (cmd, "ls") == 0) pod2text ("ls - list the files in a directory", " ls \n\nList the files in C (relative to the root directory,\nthere is no cwd). The '.' and '..' entries are not returned, but\nhidden files are shown.\n\nThis command is mostly useful for interactive sessions. Programs\nshould probably use C instead."); else - if (strcasecmp (cmd, "mount") == 0) - pod2text ("mount - mount a guest disk at a position in the filesystem", " mount \n\nMount a guest disk at a position in the filesystem. Block devices\nare named C, C and so on, as they were added to\nthe guest. If those block devices contain partitions, they will have\nthe usual names (eg. C). Also LVM C-style\nnames can be used.\n\nThe rules are the same as for L: A filesystem must\nfirst be mounted on C before others can be mounted. Other\nfilesystems can only be mounted on directories which already\nexist.\n\nThe mounted filesystem is writable, if we have sufficient permissions\non the underlying device.\n\nThe filesystem options C and C are set with this\ncall, in order to improve reliability."); + if (strcasecmp (cmd, "list_devices") == 0 || strcasecmp (cmd, "list-devices") == 0) + pod2text ("list-devices - list the block devices", " list-devices\n\nList all the block devices.\n\nThe full block device names are returned, eg. C\n"); else - if (strcasecmp (cmd, "sync") == 0) - pod2text ("sync - sync disks, writes are flushed through to the disk image", " sync\n\nThis syncs the disk, so that any writes are flushed through to the\nunderlying disk image.\n\nYou should always call this if you have modified a disk image, before\ncalling C."); - else - if (strcasecmp (cmd, "touch") == 0) - pod2text ("touch - update file timestamps or create a new file", " touch \n\nTouch acts like the L command. It can be used to\nupdate the timestamps on a file, or, if the file does not exist,\nto create a new zero-length file."); + if (strcasecmp (cmd, "list_partitions") == 0 || strcasecmp (cmd, "list-partitions") == 0) + pod2text ("list-partitions - list the partitions", " list-partitions\n\nList all the partitions detected on all block devices.\n\nThe full partition device names are returned, eg. C\n\nThis does not return logical volumes. For that you will need to\ncall C."); else display_builtin_command (cmd); } +static int run_mount (const char *cmd, int argc, char *argv[]) +{ + int r; + const char *device; + const char *mountpoint; + if (argc != 2) { + fprintf (stderr, "%s should have 2 parameter(s)\n", cmd); + fprintf (stderr, "type 'help %s' for help on %s\n", cmd, cmd); + return -1; + } + device = argv[0]; + mountpoint = argv[1]; + r = guestfs_mount (g, device, mountpoint); + return r; +} + +static int run_sync (const char *cmd, int argc, char *argv[]) +{ + int r; + if (argc != 0) { + fprintf (stderr, "%s should have 0 parameter(s)\n", cmd); + fprintf (stderr, "type 'help %s' for help on %s\n", cmd, cmd); + return -1; + } + r = guestfs_sync (g); + return r; +} + +static int run_touch (const char *cmd, int argc, char *argv[]) +{ + int r; + const char *path; + if (argc != 1) { + fprintf (stderr, "%s should have 1 parameter(s)\n", cmd); + fprintf (stderr, "type 'help %s' for help on %s\n", cmd, cmd); + return -1; + } + path = argv[0]; + r = guestfs_touch (g, path); + return r; +} + static int run_cat (const char *cmd, int argc, char *argv[]) { char *r; @@ -112,50 +162,47 @@ static int run_ls (const char *cmd, int argc, char *argv[]) return 0; } -static int run_mount (const char *cmd, int argc, char *argv[]) +static int run_list_devices (const char *cmd, int argc, char *argv[]) { - int r; - const char *device; - const char *mountpoint; - if (argc != 2) { - fprintf (stderr, "%s should have 2 parameter(s)\n", cmd); - fprintf (stderr, "type 'help %s' for help on %s\n", cmd, cmd); - return -1; - } - device = argv[0]; - mountpoint = argv[1]; - r = guestfs_mount (g, device, mountpoint); - return r; -} - -static int run_sync (const char *cmd, int argc, char *argv[]) -{ - int r; + char **r; if (argc != 0) { fprintf (stderr, "%s should have 0 parameter(s)\n", cmd); fprintf (stderr, "type 'help %s' for help on %s\n", cmd, cmd); return -1; } - r = guestfs_sync (g); - return r; + r = guestfs_list_devices (g); + if (r == NULL) return -1; + print_strings (r); + free_strings (r); + return 0; } -static int run_touch (const char *cmd, int argc, char *argv[]) +static int run_list_partitions (const char *cmd, int argc, char *argv[]) { - int r; - const char *path; - if (argc != 1) { - fprintf (stderr, "%s should have 1 parameter(s)\n", cmd); + char **r; + if (argc != 0) { + fprintf (stderr, "%s should have 0 parameter(s)\n", cmd); fprintf (stderr, "type 'help %s' for help on %s\n", cmd, cmd); return -1; } - path = argv[0]; - r = guestfs_touch (g, path); - return r; + r = guestfs_list_partitions (g); + if (r == NULL) return -1; + print_strings (r); + free_strings (r); + return 0; } int run_action (const char *cmd, int argc, char *argv[]) { + if (strcasecmp (cmd, "mount") == 0) + return run_mount (cmd, argc, argv); + else + if (strcasecmp (cmd, "sync") == 0) + return run_sync (cmd, argc, argv); + else + if (strcasecmp (cmd, "touch") == 0) + return run_touch (cmd, argc, argv); + else if (strcasecmp (cmd, "cat") == 0) return run_cat (cmd, argc, argv); else @@ -165,14 +212,11 @@ int run_action (const char *cmd, int argc, char *argv[]) if (strcasecmp (cmd, "ls") == 0) return run_ls (cmd, argc, argv); else - if (strcasecmp (cmd, "mount") == 0) - return run_mount (cmd, argc, argv); + if (strcasecmp (cmd, "list_devices") == 0 || strcasecmp (cmd, "list-devices") == 0) + return run_list_devices (cmd, argc, argv); else - if (strcasecmp (cmd, "sync") == 0) - return run_sync (cmd, argc, argv); - else - if (strcasecmp (cmd, "touch") == 0) - return run_touch (cmd, argc, argv); + if (strcasecmp (cmd, "list_partitions") == 0 || strcasecmp (cmd, "list-partitions") == 0) + return run_list_partitions (cmd, argc, argv); else { fprintf (stderr, "%s: unknown command\n", cmd); diff --git a/guestfs-actions.pod b/guestfs-actions.pod index eec6697..f89ae26 100644 --- a/guestfs-actions.pod +++ b/guestfs-actions.pod @@ -7,16 +7,44 @@ Return the contents of the file named C. Note that this function cannot correctly handle binary files (specifically, files containing C<\0> character which is treated -as end of string). For those you need to use the C +as end of string). For those you need to use the C function which has a more complex interface. -This function returns a string or NULL on error. The caller -must free the returned string after use. +This function returns a string or NULL on error. +I. Because of the message protocol, there is a transfer limit of somewhere between 2MB and 4MB. To transfer large files you should use FTP. +=head2 guestfs_list_devices + + char **guestfs_list_devices (guestfs_h *handle); + +List all the block devices. + +The full block device names are returned, eg. C + + +This function returns a NULL-terminated array of strings +(like L), or NULL if there was an error. +I. + +=head2 guestfs_list_partitions + + char **guestfs_list_partitions (guestfs_h *handle); + +List all the partitions detected on all block devices. + +The full partition device names are returned, eg. C + +This does not return logical volumes. For that you will need to +call C. + +This function returns a NULL-terminated array of strings +(like L), or NULL if there was an error. +I. + =head2 guestfs_ll char *guestfs_ll (guestfs_h *handle, @@ -28,8 +56,8 @@ there is no cwd) in the format of 'ls -la'. This command is mostly useful for interactive sessions. It is I intended that you try to parse the output string. -This function returns a string or NULL on error. The caller -must free the returned string after use. +This function returns a string or NULL on error. +I. =head2 guestfs_ls @@ -45,8 +73,7 @@ should probably use C instead. This function returns a NULL-terminated array of strings (like L), or NULL if there was an error. - -The caller must free the strings I the array after use. +I. =head2 guestfs_mount diff --git a/src/generator.ml b/src/generator.ml index da35a0f..12c51fc 100755 --- a/src/generator.ml +++ b/src/generator.ml @@ -48,35 +48,6 @@ and argt = type flags = ProtocolLimitWarning let functions = [ - ("cat", (RString "content", P1 (String "path")), 4, [ProtocolLimitWarning], - "list the contents of a file", - "\ -Return the contents of the file named C. - -Note that this function cannot correctly handle binary files -(specifically, files containing C<\\0> character which is treated -as end of string). For those you need to use the C -function which has a more complex interface."); - - ("ll", (RString "listing", P1 (String "directory")), 5, [], - "list the files in a directory (long format)", - "\ -List the files in C (relative to the root directory, -there is no cwd) in the format of 'ls -la'. - -This command is mostly useful for interactive sessions. It -is I intended that you try to parse the output string."); - - ("ls", (RStringList "listing", P1 (String "directory")), 6, [], - "list the files in a directory", - "\ -List the files in C (relative to the root directory, -there is no cwd). The '.' and '..' entries are not returned, but -hidden files are shown. - -This command is mostly useful for interactive sessions. Programs -should probably use C instead."); - ("mount", (Err, P2 (String "device", String "mountpoint")), 1, [], "mount a guest disk at a position in the filesystem", "\ @@ -112,8 +83,74 @@ calling C."); Touch acts like the L command. It can be used to update the timestamps on a file, or, if the file does not exist, to create a new zero-length file."); + + ("cat", (RString "content", P1 (String "path")), 4, [ProtocolLimitWarning], + "list the contents of a file", + "\ +Return the contents of the file named C. + +Note that this function cannot correctly handle binary files +(specifically, files containing C<\\0> character which is treated +as end of string). For those you need to use the C +function which has a more complex interface."); + + ("ll", (RString "listing", P1 (String "directory")), 5, [], + "list the files in a directory (long format)", + "\ +List the files in C (relative to the root directory, +there is no cwd) in the format of 'ls -la'. + +This command is mostly useful for interactive sessions. It +is I intended that you try to parse the output string."); + + ("ls", (RStringList "listing", P1 (String "directory")), 6, [], + "list the files in a directory", + "\ +List the files in C (relative to the root directory, +there is no cwd). The '.' and '..' entries are not returned, but +hidden files are shown. + +This command is mostly useful for interactive sessions. Programs +should probably use C instead."); + + ("list_devices", (RStringList "devices", P0), 7, [], + "list the block devices", + "\ +List all the block devices. + +The full block device names are returned, eg. C +"); + + ("list_partitions", (RStringList "partitions", P0), 8, [], + "list the partitions", + "\ +List all the partitions detected on all block devices. + +The full partition device names are returned, eg. C + +This does not return logical volumes. For that you will need to +call C."); ] +(* In some places we want the functions to be displayed sorted + * alphabetically, so this is useful: + *) +let sorted_functions = + List.sort (fun (n1,_,_,_,_,_) (n2,_,_,_,_,_) -> compare n1 n2) functions + +(* Useful functions. *) +let failwithf fs = ksprintf failwith fs +let replace s c1 c2 = + let s2 = String.copy s in + let r = ref false in + for i = 0 to String.length s2 - 1 do + if String.unsafe_get s2 i = c1 then ( + String.unsafe_set s2 i c2; + r := true + ) + done; + if not !r then s else s2 + (* 'pr' prints to the current output file. *) let chan = ref stdout let pr fs = ksprintf (output_string !chan) fs @@ -135,6 +172,30 @@ let map_args f = function let nr_args = function | P0 -> 0 | P1 _ -> 1 | P2 _ -> 2 +(* Check function names etc. for consistency. *) +let check_functions () = + List.iter ( + fun (name, _, _, _, _, _) -> + if String.contains name '-' then + failwithf "Function name '%s' should not contain '-', use '_' instead." + name + ) functions; + + let proc_nrs = + List.map (fun (name, _, proc_nr, _, _, _) -> name, proc_nr) functions in + let proc_nrs = + List.sort (fun (_,nr1) (_,nr2) -> compare nr1 nr2) proc_nrs in + let rec loop = function + | [] -> () + | [_] -> () + | (name1,nr1) :: ((name2,nr2) :: _ as rest) when nr1 < nr2 -> + loop rest + | (name1,nr1) :: (name2,nr2) :: _ -> + failwithf "'%s' and '%s' have conflicting procedure numbers (%d, %d)" + name1 name2 nr1 nr2 + in + loop proc_nrs + type comment_style = CStyle | HashStyle | OCamlStyle type license = GPLv2 | LGPLv2 @@ -202,19 +263,18 @@ and generate_pod () = | Err -> pr "This function returns 0 on success or -1 on error.\n\n" | RString _ -> - pr "This function returns a string or NULL on error. The caller -must free the returned string after use.\n\n" + pr "This function returns a string or NULL on error. +I.\n\n" | RStringList _ -> pr "This function returns a NULL-terminated array of strings (like L), or NULL if there was an error. - -The caller must free the strings I the array after use.\n\n" +I.\n\n" ); if List.mem ProtocolLimitWarning flags then pr "Because of the message protocol, there is a transfer limit of somewhere between 2MB and 4MB. To transfer large files you should use FTP.\n\n"; - ) functions + ) sorted_functions (* Generate the protocol (XDR) file. *) and generate_xdr () = @@ -562,9 +622,10 @@ and generate_fish_cmds () = pr " list_builtin_commands ();\n"; List.iter ( fun (name, _, _, _, shortdesc, _) -> + let name = replace name '_' '-' in pr " printf (\"%%-20s %%s\\n\", \"%s\", \"%s\");\n" name shortdesc - ) functions; + ) sorted_functions; pr " printf (\" Use -h / help to show detailed help for a command.\\n\");\n"; pr "}\n"; pr "\n"; @@ -574,12 +635,13 @@ and generate_fish_cmds () = pr "{\n"; List.iter ( fun (name, style, _, flags, shortdesc, longdesc) -> + let name2 = replace name '_' '-' in let synopsis = match snd style with - | P0 -> name + | P0 -> name2 | args -> sprintf "%s <%s>" - name ( + name2 ( String.concat "> <" ( map_args (function | String n -> n) args @@ -593,9 +655,13 @@ of somewhere between 2MB and 4MB. To transfer large files you should use FTP." else "" in - pr " if (strcasecmp (cmd, \"%s\") == 0)\n" name; + pr " if ("; + pr "strcasecmp (cmd, \"%s\") == 0" name; + if name <> name2 then + pr " || strcasecmp (cmd, \"%s\") == 0" name2; + pr ")\n"; pr " pod2text (\"%s - %s\", %S);\n" - name shortdesc + name2 shortdesc (" " ^ synopsis ^ "\n\n" ^ longdesc ^ warnings); pr " else\n" ) functions; @@ -660,7 +726,12 @@ FTP." pr "{\n"; List.iter ( fun (name, _, _, _, _, _) -> - pr " if (strcasecmp (cmd, \"%s\") == 0)\n" name; + let name2 = replace name '_' '-' in + pr " if ("; + pr "strcasecmp (cmd, \"%s\") == 0" name; + if name <> name2 then + pr " || strcasecmp (cmd, \"%s\") == 0" name2; + pr ")\n"; pr " return run_%s (cmd, argc, argv);\n" name; pr " else\n"; ) functions; @@ -733,6 +804,8 @@ let output_to filename = (* Main program. *) let () = + check_functions (); + let close = output_to "src/guestfs_protocol.x" in generate_xdr (); close (); diff --git a/src/guestfs-actions.c b/src/guestfs-actions.c index 989424d..d2ec0c7 100644 --- a/src/guestfs-actions.c +++ b/src/guestfs-actions.c @@ -19,6 +19,211 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +struct mount_rv { + int cb_done; /* flag to indicate callback was called */ + struct guestfs_message_header hdr; + struct guestfs_message_error err; +}; + +static void mount_cb (guestfs_h *g, void *data, XDR *xdr) +{ + struct mount_rv *rv = (struct mount_rv *) data; + + if (!xdr_guestfs_message_header (xdr, &rv->hdr)) { + error (g, "guestfs_mount: failed to parse reply header"); + return; + } + if (rv->hdr.status == GUESTFS_STATUS_ERROR) { + if (!xdr_guestfs_message_error (xdr, &rv->err)) { + error (g, "guestfs_mount: failed to parse reply error"); + return; + } + goto done; + } + done: + rv->cb_done = 1; + main_loop.main_loop_quit (g); +} + +int guestfs_mount (guestfs_h *g, + const char *device, + const char *mountpoint) +{ + struct guestfs_mount_args args; + struct mount_rv rv; + int serial; + + if (g->state != READY) { + error (g, "guestfs_mount called from the wrong state, %d != READY", + g->state); + return -1; + } + + memset (&rv, 0, sizeof rv); + + args.device = (char *) device; + args.mountpoint = (char *) mountpoint; + serial = dispatch (g, GUESTFS_PROC_MOUNT, + (xdrproc_t) xdr_guestfs_mount_args, (char *) &args); + if (serial == -1) + return -1; + + rv.cb_done = 0; + g->reply_cb_internal = mount_cb; + g->reply_cb_internal_data = &rv; + main_loop.main_loop_run (g); + g->reply_cb_internal = NULL; + g->reply_cb_internal_data = NULL; + if (!rv.cb_done) { + error (g, "guestfs_mount failed, see earlier error messages"); + return -1; + } + + if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_MOUNT, serial) == -1) + return -1; + + if (rv.hdr.status == GUESTFS_STATUS_ERROR) { + error (g, "%s", rv.err.error); + return -1; + } + + return 0; +} + +struct sync_rv { + int cb_done; /* flag to indicate callback was called */ + struct guestfs_message_header hdr; + struct guestfs_message_error err; +}; + +static void sync_cb (guestfs_h *g, void *data, XDR *xdr) +{ + struct sync_rv *rv = (struct sync_rv *) data; + + if (!xdr_guestfs_message_header (xdr, &rv->hdr)) { + error (g, "guestfs_sync: failed to parse reply header"); + return; + } + if (rv->hdr.status == GUESTFS_STATUS_ERROR) { + if (!xdr_guestfs_message_error (xdr, &rv->err)) { + error (g, "guestfs_sync: failed to parse reply error"); + return; + } + goto done; + } + done: + rv->cb_done = 1; + main_loop.main_loop_quit (g); +} + +int guestfs_sync (guestfs_h *g) +{ + struct sync_rv rv; + int serial; + + if (g->state != READY) { + error (g, "guestfs_sync called from the wrong state, %d != READY", + g->state); + return -1; + } + + memset (&rv, 0, sizeof rv); + + serial = dispatch (g, GUESTFS_PROC_SYNC, NULL, NULL); + if (serial == -1) + return -1; + + rv.cb_done = 0; + g->reply_cb_internal = sync_cb; + g->reply_cb_internal_data = &rv; + main_loop.main_loop_run (g); + g->reply_cb_internal = NULL; + g->reply_cb_internal_data = NULL; + if (!rv.cb_done) { + error (g, "guestfs_sync failed, see earlier error messages"); + return -1; + } + + if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_SYNC, serial) == -1) + return -1; + + if (rv.hdr.status == GUESTFS_STATUS_ERROR) { + error (g, "%s", rv.err.error); + return -1; + } + + return 0; +} + +struct touch_rv { + int cb_done; /* flag to indicate callback was called */ + struct guestfs_message_header hdr; + struct guestfs_message_error err; +}; + +static void touch_cb (guestfs_h *g, void *data, XDR *xdr) +{ + struct touch_rv *rv = (struct touch_rv *) data; + + if (!xdr_guestfs_message_header (xdr, &rv->hdr)) { + error (g, "guestfs_touch: failed to parse reply header"); + return; + } + if (rv->hdr.status == GUESTFS_STATUS_ERROR) { + if (!xdr_guestfs_message_error (xdr, &rv->err)) { + error (g, "guestfs_touch: failed to parse reply error"); + return; + } + goto done; + } + done: + rv->cb_done = 1; + main_loop.main_loop_quit (g); +} + +int guestfs_touch (guestfs_h *g, + const char *path) +{ + struct guestfs_touch_args args; + struct touch_rv rv; + int serial; + + if (g->state != READY) { + error (g, "guestfs_touch called from the wrong state, %d != READY", + g->state); + return -1; + } + + memset (&rv, 0, sizeof rv); + + args.path = (char *) path; + serial = dispatch (g, GUESTFS_PROC_TOUCH, + (xdrproc_t) xdr_guestfs_touch_args, (char *) &args); + if (serial == -1) + return -1; + + rv.cb_done = 0; + g->reply_cb_internal = touch_cb; + g->reply_cb_internal_data = &rv; + main_loop.main_loop_run (g); + g->reply_cb_internal = NULL; + g->reply_cb_internal_data = NULL; + if (!rv.cb_done) { + error (g, "guestfs_touch failed, see earlier error messages"); + return -1; + } + + if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_TOUCH, serial) == -1) + return -1; + + if (rv.hdr.status == GUESTFS_STATUS_ERROR) { + error (g, "%s", rv.err.error); + return -1; + } + + return 0; +} + struct cat_rv { int cb_done; /* flag to indicate callback was called */ struct guestfs_message_header hdr; @@ -244,208 +449,149 @@ char **guestfs_ls (guestfs_h *g, return rv.ret.listing.listing_val; } -struct mount_rv { +struct list_devices_rv { int cb_done; /* flag to indicate callback was called */ struct guestfs_message_header hdr; struct guestfs_message_error err; + struct guestfs_list_devices_ret ret; }; -static void mount_cb (guestfs_h *g, void *data, XDR *xdr) +static void list_devices_cb (guestfs_h *g, void *data, XDR *xdr) { - struct mount_rv *rv = (struct mount_rv *) data; + struct list_devices_rv *rv = (struct list_devices_rv *) data; if (!xdr_guestfs_message_header (xdr, &rv->hdr)) { - error (g, "guestfs_mount: failed to parse reply header"); + error (g, "guestfs_list_devices: failed to parse reply header"); return; } if (rv->hdr.status == GUESTFS_STATUS_ERROR) { if (!xdr_guestfs_message_error (xdr, &rv->err)) { - error (g, "guestfs_mount: failed to parse reply error"); + error (g, "guestfs_list_devices: failed to parse reply error"); return; } goto done; } - done: - rv->cb_done = 1; - main_loop.main_loop_quit (g); -} - -int guestfs_mount (guestfs_h *g, - const char *device, - const char *mountpoint) -{ - struct guestfs_mount_args args; - struct mount_rv rv; - int serial; - - if (g->state != READY) { - error (g, "guestfs_mount called from the wrong state, %d != READY", - g->state); - return -1; - } - - memset (&rv, 0, sizeof rv); - - args.device = (char *) device; - args.mountpoint = (char *) mountpoint; - serial = dispatch (g, GUESTFS_PROC_MOUNT, - (xdrproc_t) xdr_guestfs_mount_args, (char *) &args); - if (serial == -1) - return -1; - - rv.cb_done = 0; - g->reply_cb_internal = mount_cb; - g->reply_cb_internal_data = &rv; - main_loop.main_loop_run (g); - g->reply_cb_internal = NULL; - g->reply_cb_internal_data = NULL; - if (!rv.cb_done) { - error (g, "guestfs_mount failed, see earlier error messages"); - return -1; - } - - if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_MOUNT, serial) == -1) - return -1; - - if (rv.hdr.status == GUESTFS_STATUS_ERROR) { - error (g, "%s", rv.err.error); - return -1; - } - - return 0; -} - -struct sync_rv { - int cb_done; /* flag to indicate callback was called */ - struct guestfs_message_header hdr; - struct guestfs_message_error err; -}; - -static void sync_cb (guestfs_h *g, void *data, XDR *xdr) -{ - struct sync_rv *rv = (struct sync_rv *) data; - - if (!xdr_guestfs_message_header (xdr, &rv->hdr)) { - error (g, "guestfs_sync: failed to parse reply header"); + if (!xdr_guestfs_list_devices_ret (xdr, &rv->ret)) { + error (g, "guestfs_list_devices: failed to parse reply"); return; } - if (rv->hdr.status == GUESTFS_STATUS_ERROR) { - if (!xdr_guestfs_message_error (xdr, &rv->err)) { - error (g, "guestfs_sync: failed to parse reply error"); - return; - } - goto done; - } done: rv->cb_done = 1; main_loop.main_loop_quit (g); } -int guestfs_sync (guestfs_h *g) +char **guestfs_list_devices (guestfs_h *g) { - struct sync_rv rv; + struct list_devices_rv rv; int serial; if (g->state != READY) { - error (g, "guestfs_sync called from the wrong state, %d != READY", + error (g, "guestfs_list_devices called from the wrong state, %d != READY", g->state); - return -1; + return NULL; } memset (&rv, 0, sizeof rv); - serial = dispatch (g, GUESTFS_PROC_SYNC, NULL, NULL); + serial = dispatch (g, GUESTFS_PROC_LIST_DEVICES, NULL, NULL); if (serial == -1) - return -1; + return NULL; rv.cb_done = 0; - g->reply_cb_internal = sync_cb; + g->reply_cb_internal = list_devices_cb; g->reply_cb_internal_data = &rv; main_loop.main_loop_run (g); g->reply_cb_internal = NULL; g->reply_cb_internal_data = NULL; if (!rv.cb_done) { - error (g, "guestfs_sync failed, see earlier error messages"); - return -1; + error (g, "guestfs_list_devices failed, see earlier error messages"); + return NULL; } - if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_SYNC, serial) == -1) - return -1; + if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_LIST_DEVICES, serial) == -1) + return NULL; if (rv.hdr.status == GUESTFS_STATUS_ERROR) { error (g, "%s", rv.err.error); - return -1; + return NULL; } - return 0; + /* caller will free this, but we need to add a NULL entry */ + rv.ret.devices.devices_val = safe_realloc (g, rv.ret.devices.devices_val, rv.ret.devices.devices_len + 1); + rv.ret.devices.devices_val[rv.ret.devices.devices_len] = NULL; + return rv.ret.devices.devices_val; } -struct touch_rv { +struct list_partitions_rv { int cb_done; /* flag to indicate callback was called */ struct guestfs_message_header hdr; struct guestfs_message_error err; + struct guestfs_list_partitions_ret ret; }; -static void touch_cb (guestfs_h *g, void *data, XDR *xdr) +static void list_partitions_cb (guestfs_h *g, void *data, XDR *xdr) { - struct touch_rv *rv = (struct touch_rv *) data; + struct list_partitions_rv *rv = (struct list_partitions_rv *) data; if (!xdr_guestfs_message_header (xdr, &rv->hdr)) { - error (g, "guestfs_touch: failed to parse reply header"); + error (g, "guestfs_list_partitions: failed to parse reply header"); return; } if (rv->hdr.status == GUESTFS_STATUS_ERROR) { if (!xdr_guestfs_message_error (xdr, &rv->err)) { - error (g, "guestfs_touch: failed to parse reply error"); + error (g, "guestfs_list_partitions: failed to parse reply error"); return; } goto done; } + if (!xdr_guestfs_list_partitions_ret (xdr, &rv->ret)) { + error (g, "guestfs_list_partitions: failed to parse reply"); + return; + } done: rv->cb_done = 1; main_loop.main_loop_quit (g); } -int guestfs_touch (guestfs_h *g, - const char *path) +char **guestfs_list_partitions (guestfs_h *g) { - struct guestfs_touch_args args; - struct touch_rv rv; + struct list_partitions_rv rv; int serial; if (g->state != READY) { - error (g, "guestfs_touch called from the wrong state, %d != READY", + error (g, "guestfs_list_partitions called from the wrong state, %d != READY", g->state); - return -1; + return NULL; } memset (&rv, 0, sizeof rv); - args.path = (char *) path; - serial = dispatch (g, GUESTFS_PROC_TOUCH, - (xdrproc_t) xdr_guestfs_touch_args, (char *) &args); + serial = dispatch (g, GUESTFS_PROC_LIST_PARTITIONS, NULL, NULL); if (serial == -1) - return -1; + return NULL; rv.cb_done = 0; - g->reply_cb_internal = touch_cb; + g->reply_cb_internal = list_partitions_cb; g->reply_cb_internal_data = &rv; main_loop.main_loop_run (g); g->reply_cb_internal = NULL; g->reply_cb_internal_data = NULL; if (!rv.cb_done) { - error (g, "guestfs_touch failed, see earlier error messages"); - return -1; + error (g, "guestfs_list_partitions failed, see earlier error messages"); + return NULL; } - if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_TOUCH, serial) == -1) - return -1; + if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_LIST_PARTITIONS, serial) == -1) + return NULL; if (rv.hdr.status == GUESTFS_STATUS_ERROR) { error (g, "%s", rv.err.error); - return -1; + return NULL; } - return 0; + /* caller will free this, but we need to add a NULL entry */ + rv.ret.partitions.partitions_val = safe_realloc (g, rv.ret.partitions.partitions_val, rv.ret.partitions.partitions_len + 1); + rv.ret.partitions.partitions_val[rv.ret.partitions.partitions_len] = NULL; + return rv.ret.partitions.partitions_val; } diff --git a/src/guestfs-actions.h b/src/guestfs-actions.h index 7f14304..7019d98 100644 --- a/src/guestfs-actions.h +++ b/src/guestfs-actions.h @@ -19,9 +19,11 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -extern char *guestfs_cat (guestfs_h *handle, const char *path); -extern char *guestfs_ll (guestfs_h *handle, const char *directory); -extern char **guestfs_ls (guestfs_h *handle, const char *directory); extern int guestfs_mount (guestfs_h *handle, const char *device, const char *mountpoint); extern int guestfs_sync (guestfs_h *handle); extern int guestfs_touch (guestfs_h *handle, const char *path); +extern char *guestfs_cat (guestfs_h *handle, const char *path); +extern char *guestfs_ll (guestfs_h *handle, const char *directory); +extern char **guestfs_ls (guestfs_h *handle, const char *directory); +extern char **guestfs_list_devices (guestfs_h *handle); +extern char **guestfs_list_partitions (guestfs_h *handle); diff --git a/src/guestfs_protocol.c b/src/guestfs_protocol.c index c51aa5d..80f618b 100644 --- a/src/guestfs_protocol.c +++ b/src/guestfs_protocol.c @@ -16,6 +16,28 @@ xdr_str (XDR *xdrs, str *objp) } bool_t +xdr_guestfs_mount_args (XDR *xdrs, guestfs_mount_args *objp) +{ + register int32_t *buf; + + if (!xdr_string (xdrs, &objp->device, ~0)) + return FALSE; + if (!xdr_string (xdrs, &objp->mountpoint, ~0)) + return FALSE; + return TRUE; +} + +bool_t +xdr_guestfs_touch_args (XDR *xdrs, guestfs_touch_args *objp) +{ + register int32_t *buf; + + if (!xdr_string (xdrs, &objp->path, ~0)) + return FALSE; + return TRUE; +} + +bool_t xdr_guestfs_cat_args (XDR *xdrs, guestfs_cat_args *objp) { register int32_t *buf; @@ -77,23 +99,23 @@ xdr_guestfs_ls_ret (XDR *xdrs, guestfs_ls_ret *objp) } bool_t -xdr_guestfs_mount_args (XDR *xdrs, guestfs_mount_args *objp) +xdr_guestfs_list_devices_ret (XDR *xdrs, guestfs_list_devices_ret *objp) { register int32_t *buf; - if (!xdr_string (xdrs, &objp->device, ~0)) - return FALSE; - if (!xdr_string (xdrs, &objp->mountpoint, ~0)) + if (!xdr_array (xdrs, (char **)&objp->devices.devices_val, (u_int *) &objp->devices.devices_len, ~0, + sizeof (str), (xdrproc_t) xdr_str)) return FALSE; return TRUE; } bool_t -xdr_guestfs_touch_args (XDR *xdrs, guestfs_touch_args *objp) +xdr_guestfs_list_partitions_ret (XDR *xdrs, guestfs_list_partitions_ret *objp) { register int32_t *buf; - if (!xdr_string (xdrs, &objp->path, ~0)) + if (!xdr_array (xdrs, (char **)&objp->partitions.partitions_val, (u_int *) &objp->partitions.partitions_len, ~0, + sizeof (str), (xdrproc_t) xdr_str)) return FALSE; return TRUE; } diff --git a/src/guestfs_protocol.h b/src/guestfs_protocol.h index a83ad00..3e19212 100644 --- a/src/guestfs_protocol.h +++ b/src/guestfs_protocol.h @@ -16,6 +16,17 @@ extern "C" { typedef char *str; +struct guestfs_mount_args { + char *device; + char *mountpoint; +}; +typedef struct guestfs_mount_args guestfs_mount_args; + +struct guestfs_touch_args { + char *path; +}; +typedef struct guestfs_touch_args guestfs_touch_args; + struct guestfs_cat_args { char *path; }; @@ -49,25 +60,32 @@ struct guestfs_ls_ret { }; typedef struct guestfs_ls_ret guestfs_ls_ret; -struct guestfs_mount_args { - char *device; - char *mountpoint; +struct guestfs_list_devices_ret { + struct { + u_int devices_len; + str *devices_val; + } devices; }; -typedef struct guestfs_mount_args guestfs_mount_args; +typedef struct guestfs_list_devices_ret guestfs_list_devices_ret; -struct guestfs_touch_args { - char *path; +struct guestfs_list_partitions_ret { + struct { + u_int partitions_len; + str *partitions_val; + } partitions; }; -typedef struct guestfs_touch_args guestfs_touch_args; +typedef struct guestfs_list_partitions_ret guestfs_list_partitions_ret; enum guestfs_procedure { - GUESTFS_PROC_CAT = 4, - GUESTFS_PROC_LL = 5, - GUESTFS_PROC_LS = 6, GUESTFS_PROC_MOUNT = 1, GUESTFS_PROC_SYNC = 2, GUESTFS_PROC_TOUCH = 3, - GUESTFS_PROC_dummy = 3 + 1, + GUESTFS_PROC_CAT = 4, + GUESTFS_PROC_LL = 5, + GUESTFS_PROC_LS = 6, + GUESTFS_PROC_LIST_DEVICES = 7, + GUESTFS_PROC_LIST_PARTITIONS = 8, + GUESTFS_PROC_dummy = 8 + 1, }; typedef enum guestfs_procedure guestfs_procedure; #define GUESTFS_MESSAGE_MAX 4194304 @@ -106,14 +124,16 @@ typedef struct guestfs_message_header guestfs_message_header; #if defined(__STDC__) || defined(__cplusplus) extern bool_t xdr_str (XDR *, str*); +extern bool_t xdr_guestfs_mount_args (XDR *, guestfs_mount_args*); +extern bool_t xdr_guestfs_touch_args (XDR *, guestfs_touch_args*); extern bool_t xdr_guestfs_cat_args (XDR *, guestfs_cat_args*); extern bool_t xdr_guestfs_cat_ret (XDR *, guestfs_cat_ret*); extern bool_t xdr_guestfs_ll_args (XDR *, guestfs_ll_args*); extern bool_t xdr_guestfs_ll_ret (XDR *, guestfs_ll_ret*); extern bool_t xdr_guestfs_ls_args (XDR *, guestfs_ls_args*); extern bool_t xdr_guestfs_ls_ret (XDR *, guestfs_ls_ret*); -extern bool_t xdr_guestfs_mount_args (XDR *, guestfs_mount_args*); -extern bool_t xdr_guestfs_touch_args (XDR *, guestfs_touch_args*); +extern bool_t xdr_guestfs_list_devices_ret (XDR *, guestfs_list_devices_ret*); +extern bool_t xdr_guestfs_list_partitions_ret (XDR *, guestfs_list_partitions_ret*); extern bool_t xdr_guestfs_procedure (XDR *, guestfs_procedure*); extern bool_t xdr_guestfs_message_direction (XDR *, guestfs_message_direction*); extern bool_t xdr_guestfs_message_status (XDR *, guestfs_message_status*); @@ -122,14 +142,16 @@ extern bool_t xdr_guestfs_message_header (XDR *, guestfs_message_header*); #else /* K&R C */ extern bool_t xdr_str (); +extern bool_t xdr_guestfs_mount_args (); +extern bool_t xdr_guestfs_touch_args (); extern bool_t xdr_guestfs_cat_args (); extern bool_t xdr_guestfs_cat_ret (); extern bool_t xdr_guestfs_ll_args (); extern bool_t xdr_guestfs_ll_ret (); extern bool_t xdr_guestfs_ls_args (); extern bool_t xdr_guestfs_ls_ret (); -extern bool_t xdr_guestfs_mount_args (); -extern bool_t xdr_guestfs_touch_args (); +extern bool_t xdr_guestfs_list_devices_ret (); +extern bool_t xdr_guestfs_list_partitions_ret (); extern bool_t xdr_guestfs_procedure (); extern bool_t xdr_guestfs_message_direction (); extern bool_t xdr_guestfs_message_status (); diff --git a/src/guestfs_protocol.x b/src/guestfs_protocol.x index df3e936..be0efdb 100644 --- a/src/guestfs_protocol.x +++ b/src/guestfs_protocol.x @@ -21,6 +21,21 @@ typedef string str<>; +/* guestfs_mount */ + +struct guestfs_mount_args { + string device<>; + string mountpoint<>; +}; + +/* guestfs_sync */ + +/* guestfs_touch */ + +struct guestfs_touch_args { + string path<>; +}; + /* guestfs_cat */ struct guestfs_cat_args { @@ -51,28 +66,27 @@ struct guestfs_ls_ret { str listing<>; }; -/* guestfs_mount */ +/* guestfs_list_devices */ -struct guestfs_mount_args { - string device<>; - string mountpoint<>; +struct guestfs_list_devices_ret { + str devices<>; }; -/* guestfs_sync */ - -/* guestfs_touch */ +/* guestfs_list_partitions */ -struct guestfs_touch_args { - string path<>; +struct guestfs_list_partitions_ret { + str partitions<>; }; enum guestfs_procedure { - GUESTFS_PROC_CAT = 4, - GUESTFS_PROC_LL = 5, - GUESTFS_PROC_LS = 6, GUESTFS_PROC_MOUNT = 1, GUESTFS_PROC_SYNC = 2, GUESTFS_PROC_TOUCH = 3, + GUESTFS_PROC_CAT = 4, + GUESTFS_PROC_LL = 5, + GUESTFS_PROC_LS = 6, + GUESTFS_PROC_LIST_DEVICES = 7, + GUESTFS_PROC_LIST_PARTITIONS = 8, GUESTFS_PROC_dummy }; -- 1.8.3.1