mirror of
https://github.com/libguestfs/libguestfs.git
synced 2026-03-21 22:53:37 +00:00
Added stat, lstat, statvfs and associated stat structures.
This commit is contained in:
@@ -31,6 +31,7 @@ guestfsd_SOURCES = \
|
||||
lvm.c \
|
||||
mount.c \
|
||||
proto.c \
|
||||
stat.c \
|
||||
stubs.c \
|
||||
sync.c \
|
||||
../src/guestfs_protocol.h \
|
||||
|
||||
155
daemon/stat.c
Normal file
155
daemon/stat.c
Normal file
@@ -0,0 +1,155 @@
|
||||
/* 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 <config.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/statvfs.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "../src/guestfs_protocol.h"
|
||||
#include "daemon.h"
|
||||
#include "actions.h"
|
||||
|
||||
guestfs_int_stat *
|
||||
do_stat (const char *path)
|
||||
{
|
||||
int r;
|
||||
guestfs_int_stat *ret;
|
||||
struct stat statbuf;
|
||||
|
||||
NEED_ROOT (NULL);
|
||||
ABS_PATH (path, NULL);
|
||||
|
||||
CHROOT_IN;
|
||||
r = stat (path, &statbuf);
|
||||
CHROOT_OUT;
|
||||
|
||||
if (r == -1) {
|
||||
reply_with_perror ("stat");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret = malloc (sizeof *ret);
|
||||
if (ret == NULL) {
|
||||
reply_with_perror ("malloc");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret->dev = statbuf.st_dev;
|
||||
ret->ino = statbuf.st_ino;
|
||||
ret->mode = statbuf.st_mode;
|
||||
ret->nlink = statbuf.st_nlink;
|
||||
ret->uid = statbuf.st_uid;
|
||||
ret->gid = statbuf.st_gid;
|
||||
ret->rdev = statbuf.st_rdev;
|
||||
ret->size = statbuf.st_size;
|
||||
ret->blksize = statbuf.st_blksize;
|
||||
ret->blocks = statbuf.st_blocks;
|
||||
ret->atime = statbuf.st_atime;
|
||||
ret->mtime = statbuf.st_mtime;
|
||||
ret->ctime = statbuf.st_ctime;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
guestfs_int_stat *
|
||||
do_lstat (const char *path)
|
||||
{
|
||||
int r;
|
||||
guestfs_int_stat *ret;
|
||||
struct stat statbuf;
|
||||
|
||||
NEED_ROOT (NULL);
|
||||
ABS_PATH (path, NULL);
|
||||
|
||||
CHROOT_IN;
|
||||
r = lstat (path, &statbuf);
|
||||
CHROOT_OUT;
|
||||
|
||||
if (r == -1) {
|
||||
reply_with_perror ("stat");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret = malloc (sizeof *ret);
|
||||
if (ret == NULL) {
|
||||
reply_with_perror ("malloc");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret->dev = statbuf.st_dev;
|
||||
ret->ino = statbuf.st_ino;
|
||||
ret->mode = statbuf.st_mode;
|
||||
ret->nlink = statbuf.st_nlink;
|
||||
ret->uid = statbuf.st_uid;
|
||||
ret->gid = statbuf.st_gid;
|
||||
ret->rdev = statbuf.st_rdev;
|
||||
ret->size = statbuf.st_size;
|
||||
ret->blksize = statbuf.st_blksize;
|
||||
ret->blocks = statbuf.st_blocks;
|
||||
ret->atime = statbuf.st_atime;
|
||||
ret->mtime = statbuf.st_mtime;
|
||||
ret->ctime = statbuf.st_ctime;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
guestfs_int_statvfs *
|
||||
do_statvfs (const char *path)
|
||||
{
|
||||
int r;
|
||||
guestfs_int_statvfs *ret;
|
||||
struct statvfs statbuf;
|
||||
|
||||
NEED_ROOT (NULL);
|
||||
ABS_PATH (path, NULL);
|
||||
|
||||
CHROOT_IN;
|
||||
r = statvfs (path, &statbuf);
|
||||
CHROOT_OUT;
|
||||
|
||||
if (r == -1) {
|
||||
reply_with_perror ("statvfs");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret = malloc (sizeof *ret);
|
||||
if (ret == NULL) {
|
||||
reply_with_perror ("malloc");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret->bsize = statbuf.f_bsize;
|
||||
ret->frsize = statbuf.f_frsize;
|
||||
ret->blocks = statbuf.f_blocks;
|
||||
ret->bfree = statbuf.f_bfree;
|
||||
ret->bavail = statbuf.f_bavail;
|
||||
ret->files = statbuf.f_files;
|
||||
ret->ffree = statbuf.f_ffree;
|
||||
ret->favail = statbuf.f_favail;
|
||||
ret->fsid = statbuf.f_fsid;
|
||||
ret->flag = statbuf.f_flag;
|
||||
ret->namemax = statbuf.f_namemax;
|
||||
|
||||
return ret;
|
||||
}
|
||||
415
src/generator.ml
415
src/generator.ml
@@ -65,6 +65,9 @@ and ret =
|
||||
| RPVList of string
|
||||
| RVGList of string
|
||||
| RLVList of string
|
||||
(* Stat buffers. *)
|
||||
| RStat of string
|
||||
| RStatVFS of string
|
||||
and args = argt list (* Function parameters, guestfs handle is implicit. *)
|
||||
|
||||
(* Note in future we should allow a "variable args" parameter as
|
||||
@@ -107,7 +110,7 @@ can easily destroy all your data>."
|
||||
* the virtual machine and block devices are reused between tests.
|
||||
* So don't try testing kill_subprocess :-x
|
||||
*
|
||||
* Between each test we umount-all and lvm-remove-all.
|
||||
* Between each test we umount-all and lvm-remove-all (except InitNone).
|
||||
*
|
||||
* Don't assume anything about the previous contents of the block
|
||||
* devices. Use 'Init*' to create some initial scenarios.
|
||||
@@ -141,11 +144,21 @@ and test =
|
||||
* content).
|
||||
*)
|
||||
| TestOutputLength of seq * int
|
||||
(* Run the command sequence and expect the output of the final
|
||||
* command to be a structure.
|
||||
*)
|
||||
| TestOutputStruct of seq * test_field_compare list
|
||||
(* Run the command sequence and expect the final command (only)
|
||||
* to fail.
|
||||
*)
|
||||
| TestLastFail of seq
|
||||
|
||||
and test_field_compare =
|
||||
| CompareWithInt of string * int
|
||||
| CompareWithString of string * string
|
||||
| CompareFieldsIntEq of string * string
|
||||
| CompareFieldsStrEq of string * string
|
||||
|
||||
(* Some initial scenarios for testing. *)
|
||||
and test_init =
|
||||
(* Do nothing, block devices could contain random stuff including
|
||||
@@ -475,24 +488,21 @@ This returns a list of the logical volume device names
|
||||
See also C<guestfs_lvs_full>.");
|
||||
|
||||
("pvs_full", (RPVList "physvols", []), 12, [],
|
||||
[InitBasicFSonLVM, TestOutputLength (
|
||||
[["pvs"]], 1)],
|
||||
[], (* XXX how to test? *)
|
||||
"list the LVM physical volumes (PVs)",
|
||||
"\
|
||||
List all the physical volumes detected. This is the equivalent
|
||||
of the L<pvs(8)> command. The \"full\" version includes all fields.");
|
||||
|
||||
("vgs_full", (RVGList "volgroups", []), 13, [],
|
||||
[InitBasicFSonLVM, TestOutputLength (
|
||||
[["pvs"]], 1)],
|
||||
[], (* XXX how to test? *)
|
||||
"list the LVM volume groups (VGs)",
|
||||
"\
|
||||
List all the volumes groups detected. This is the equivalent
|
||||
of the L<vgs(8)> command. The \"full\" version includes all fields.");
|
||||
|
||||
("lvs_full", (RLVList "logvols", []), 14, [],
|
||||
[InitBasicFSonLVM, TestOutputLength (
|
||||
[["pvs"]], 1)],
|
||||
[], (* XXX how to test? *)
|
||||
"list the LVM logical volumes (LVs)",
|
||||
"\
|
||||
List all the logical volumes detected. This is the equivalent
|
||||
@@ -1001,6 +1011,43 @@ locations.");
|
||||
This is the same as C<guestfs_command>, but splits the
|
||||
result into a list of lines.");
|
||||
|
||||
("stat", (RStat "statbuf", [String "path"]), 52, [],
|
||||
[InitBasicFS, TestOutputStruct (
|
||||
[["touch"; "/new"];
|
||||
["stat"; "/new"]], [CompareWithInt ("size", 0)])],
|
||||
"get file information",
|
||||
"\
|
||||
Returns file information for the given C<path>.
|
||||
|
||||
This is the same as the C<stat(2)> system call.");
|
||||
|
||||
("lstat", (RStat "statbuf", [String "path"]), 53, [],
|
||||
[InitBasicFS, TestOutputStruct (
|
||||
[["touch"; "/new"];
|
||||
["lstat"; "/new"]], [CompareWithInt ("size", 0)])],
|
||||
"get file information for a symbolic link",
|
||||
"\
|
||||
Returns file information for the given C<path>.
|
||||
|
||||
This is the same as C<guestfs_stat> except that if C<path>
|
||||
is a symbolic link, then the link is stat-ed, not the file it
|
||||
refers to.
|
||||
|
||||
This is the same as the C<lstat(2)> system call.");
|
||||
|
||||
("statvfs", (RStatVFS "statbuf", [String "path"]), 54, [],
|
||||
[InitBasicFS, TestOutputStruct (
|
||||
[["statvfs"; "/"]], [CompareWithInt ("bfree", 487702);
|
||||
CompareWithInt ("blocks", 490020);
|
||||
CompareWithInt ("bsize", 1024)])],
|
||||
"get file system statistics",
|
||||
"\
|
||||
Returns file system statistics for any mounted file system.
|
||||
C<path> should be a file or directory in the mounted file system
|
||||
(typically it is the mount point itself, but it doesn't need to be).
|
||||
|
||||
This is the same as the C<statvfs(2)> system call.");
|
||||
|
||||
]
|
||||
|
||||
let all_functions = non_daemon_functions @ daemon_functions
|
||||
@@ -1075,6 +1122,39 @@ let lv_cols = [
|
||||
"modules", `String;
|
||||
]
|
||||
|
||||
(* Column names and types from stat structures.
|
||||
* NB. Can't use things like 'st_atime' because glibc header files
|
||||
* define some of these as macros. Ugh.
|
||||
*)
|
||||
let stat_cols = [
|
||||
"dev", `Int;
|
||||
"ino", `Int;
|
||||
"mode", `Int;
|
||||
"nlink", `Int;
|
||||
"uid", `Int;
|
||||
"gid", `Int;
|
||||
"rdev", `Int;
|
||||
"size", `Int;
|
||||
"blksize", `Int;
|
||||
"blocks", `Int;
|
||||
"atime", `Int;
|
||||
"mtime", `Int;
|
||||
"ctime", `Int;
|
||||
]
|
||||
let statvfs_cols = [
|
||||
"bsize", `Int;
|
||||
"frsize", `Int;
|
||||
"blocks", `Int;
|
||||
"bfree", `Int;
|
||||
"bavail", `Int;
|
||||
"files", `Int;
|
||||
"ffree", `Int;
|
||||
"favail", `Int;
|
||||
"fsid", `Int;
|
||||
"flag", `Int;
|
||||
"namemax", `Int;
|
||||
]
|
||||
|
||||
(* Useful functions.
|
||||
* Note we don't want to use any external OCaml libraries which
|
||||
* makes this a bit harder than it should be.
|
||||
@@ -1203,7 +1283,8 @@ let check_functions () =
|
||||
(match fst style with
|
||||
| RErr -> ()
|
||||
| RInt n | RBool n | RConstString n | RString n
|
||||
| RStringList n | RPVList n | RVGList n | RLVList n ->
|
||||
| RStringList n | RPVList n | RVGList n | RLVList n
|
||||
| RStat n | RStatVFS n ->
|
||||
check_arg_ret_name n
|
||||
| RIntBool (n,m) ->
|
||||
check_arg_ret_name n;
|
||||
@@ -1345,17 +1426,34 @@ I<The caller must free the returned string after use>.\n\n"
|
||||
(like L<environ(3)>), or NULL if there was an error.
|
||||
I<The caller must free the strings and the array after use>.\n\n"
|
||||
| RIntBool _ ->
|
||||
pr "This function returns a C<struct guestfs_int_bool *>.
|
||||
pr "This function returns a C<struct guestfs_int_bool *>,
|
||||
or NULL if there was an error.
|
||||
I<The caller must call C<guestfs_free_int_bool> after use>.\n\n"
|
||||
| RPVList _ ->
|
||||
pr "This function returns a C<struct guestfs_lvm_pv_list *>.
|
||||
pr "This function returns a C<struct guestfs_lvm_pv_list *>
|
||||
(see E<lt>guestfs-structs.hE<gt>),
|
||||
or NULL if there was an error.
|
||||
I<The caller must call C<guestfs_free_lvm_pv_list> after use>.\n\n"
|
||||
| RVGList _ ->
|
||||
pr "This function returns a C<struct guestfs_lvm_vg_list *>.
|
||||
pr "This function returns a C<struct guestfs_lvm_vg_list *>
|
||||
(see E<lt>guestfs-structs.hE<gt>),
|
||||
or NULL if there was an error.
|
||||
I<The caller must call C<guestfs_free_lvm_vg_list> after use>.\n\n"
|
||||
| RLVList _ ->
|
||||
pr "This function returns a C<struct guestfs_lvm_lv_list *>.
|
||||
pr "This function returns a C<struct guestfs_lvm_lv_list *>
|
||||
(see E<lt>guestfs-structs.hE<gt>),
|
||||
or NULL if there was an error.
|
||||
I<The caller must call C<guestfs_free_lvm_lv_list> after use>.\n\n"
|
||||
| RStat _ ->
|
||||
pr "This function returns a C<struct guestfs_stat *>
|
||||
(see L<stat(2)> and E<lt>guestfs-structs.hE<gt>),
|
||||
or NULL if there was an error.
|
||||
I<The caller must call C<free> after use>.\n\n"
|
||||
| RStatVFS _ ->
|
||||
pr "This function returns a C<struct guestfs_statvfs *>
|
||||
(see L<statvfs(2)> and E<lt>guestfs-structs.hE<gt>),
|
||||
or NULL if there was an error.
|
||||
I<The caller must call C<free> after use>.\n\n"
|
||||
);
|
||||
if List.mem ProtocolLimitWarning flags then
|
||||
pr "%s\n\n" protocol_limit_warning;
|
||||
@@ -1426,6 +1524,18 @@ and generate_xdr () =
|
||||
pr "\n";
|
||||
) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
|
||||
|
||||
(* Stat internal structures. *)
|
||||
List.iter (
|
||||
function
|
||||
| typ, cols ->
|
||||
pr "struct guestfs_int_%s {\n" typ;
|
||||
List.iter (function
|
||||
| name, `Int -> pr " hyper %s;\n" name
|
||||
) cols;
|
||||
pr "};\n";
|
||||
pr "\n";
|
||||
) ["stat", stat_cols; "statvfs", statvfs_cols];
|
||||
|
||||
List.iter (
|
||||
fun (shortname, style, _, _, _, _, _) ->
|
||||
let name = "guestfs_" ^ shortname in
|
||||
@@ -1481,6 +1591,14 @@ and generate_xdr () =
|
||||
pr "struct %s_ret {\n" name;
|
||||
pr " guestfs_lvm_int_lv_list %s;\n" n;
|
||||
pr "};\n\n"
|
||||
| RStat n ->
|
||||
pr "struct %s_ret {\n" name;
|
||||
pr " guestfs_int_stat %s;\n" n;
|
||||
pr "};\n\n";
|
||||
| RStatVFS n ->
|
||||
pr "struct %s_ret {\n" name;
|
||||
pr " guestfs_int_statvfs %s;\n" n;
|
||||
pr "};\n\n";
|
||||
);
|
||||
) daemon_functions;
|
||||
|
||||
@@ -1579,7 +1697,20 @@ and generate_structs_h () =
|
||||
pr " struct guestfs_lvm_%s *val;\n" typ;
|
||||
pr "};\n";
|
||||
pr "\n"
|
||||
) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols]
|
||||
) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
|
||||
|
||||
(* Stat structures. *)
|
||||
List.iter (
|
||||
function
|
||||
| typ, cols ->
|
||||
pr "struct guestfs_%s {\n" typ;
|
||||
List.iter (
|
||||
function
|
||||
| name, `Int -> pr " int64_t %s;\n" name
|
||||
) cols;
|
||||
pr "};\n";
|
||||
pr "\n"
|
||||
) ["stat", stat_cols; "statvfs", statvfs_cols]
|
||||
|
||||
(* Generate the guestfs-actions.h file. *)
|
||||
and generate_actions_h () =
|
||||
@@ -1612,7 +1743,8 @@ and generate_client_actions () =
|
||||
| RInt _
|
||||
| RBool _ | RString _ | RStringList _
|
||||
| RIntBool _
|
||||
| RPVList _ | RVGList _ | RLVList _ ->
|
||||
| RPVList _ | RVGList _ | RLVList _
|
||||
| RStat _ | RStatVFS _ ->
|
||||
pr " struct %s_ret ret;\n" name
|
||||
);
|
||||
pr "};\n\n";
|
||||
@@ -1641,7 +1773,8 @@ and generate_client_actions () =
|
||||
| RInt _
|
||||
| RBool _ | RString _ | RStringList _
|
||||
| RIntBool _
|
||||
| RPVList _ | RVGList _ | RLVList _ ->
|
||||
| RPVList _ | RVGList _ | RLVList _
|
||||
| RStat _ | RStatVFS _ ->
|
||||
pr " if (!xdr_%s_ret (xdr, &rv->ret)) {\n" name;
|
||||
pr " error (g, \"%s: failed to parse reply\");\n" name;
|
||||
pr " return;\n";
|
||||
@@ -1663,7 +1796,8 @@ and generate_client_actions () =
|
||||
| RConstString _ ->
|
||||
failwithf "RConstString cannot be returned from a daemon function"
|
||||
| RString _ | RStringList _ | RIntBool _
|
||||
| RPVList _ | RVGList _ | RLVList _ ->
|
||||
| RPVList _ | RVGList _ | RLVList _
|
||||
| RStat _ | RStatVFS _ ->
|
||||
"NULL" in
|
||||
|
||||
pr "{\n";
|
||||
@@ -1765,6 +1899,12 @@ and generate_client_actions () =
|
||||
| RLVList n ->
|
||||
pr " /* caller will free this */\n";
|
||||
pr " return safe_memdup (g, &rv.ret.%s, sizeof (rv.ret.%s));\n" n n
|
||||
| RStat n ->
|
||||
pr " /* caller will free this */\n";
|
||||
pr " return safe_memdup (g, &rv.ret.%s, sizeof (rv.ret.%s));\n" n n
|
||||
| RStatVFS n ->
|
||||
pr " /* caller will free this */\n";
|
||||
pr " return safe_memdup (g, &rv.ret.%s, sizeof (rv.ret.%s));\n" n n
|
||||
);
|
||||
|
||||
pr "}\n\n"
|
||||
@@ -1819,7 +1959,9 @@ and generate_daemon_actions () =
|
||||
| RIntBool _ -> pr " guestfs_%s_ret *r;\n" name; "NULL"
|
||||
| RPVList _ -> pr " guestfs_lvm_int_pv_list *r;\n"; "NULL"
|
||||
| RVGList _ -> pr " guestfs_lvm_int_vg_list *r;\n"; "NULL"
|
||||
| RLVList _ -> pr " guestfs_lvm_int_lv_list *r;\n"; "NULL" in
|
||||
| RLVList _ -> pr " guestfs_lvm_int_lv_list *r;\n"; "NULL"
|
||||
| RStat _ -> pr " guestfs_int_stat *r;\n"; "NULL"
|
||||
| RStatVFS _ -> pr " guestfs_int_statvfs *r;\n"; "NULL" in
|
||||
|
||||
(match snd style with
|
||||
| [] -> ()
|
||||
@@ -1894,17 +2036,7 @@ and generate_daemon_actions () =
|
||||
| RIntBool _ ->
|
||||
pr " reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) r);\n" name;
|
||||
pr " xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) r);\n" name
|
||||
| RPVList n ->
|
||||
pr " struct guestfs_%s_ret ret;\n" name;
|
||||
pr " ret.%s = *r;\n" n;
|
||||
pr " reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n" name;
|
||||
pr " xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n" name
|
||||
| RVGList n ->
|
||||
pr " struct guestfs_%s_ret ret;\n" name;
|
||||
pr " ret.%s = *r;\n" n;
|
||||
pr " reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n" name;
|
||||
pr " xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n" name
|
||||
| RLVList n ->
|
||||
| RPVList n | RVGList n | RLVList n | RStat n | RStatVFS n ->
|
||||
pr " struct guestfs_%s_ret ret;\n" name;
|
||||
pr " ret.%s = *r;\n" n;
|
||||
pr " reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n" name;
|
||||
@@ -2156,6 +2288,7 @@ int main (int argc, char *argv[])
|
||||
const char *srcdir;
|
||||
int fd;
|
||||
char buf[256];
|
||||
int nr_tests;
|
||||
|
||||
g = guestfs_create ();
|
||||
if (g == NULL) {
|
||||
@@ -2262,11 +2395,12 @@ int main (int argc, char *argv[])
|
||||
exit (1);
|
||||
}
|
||||
|
||||
" (500 * 1024 * 1024) (50 * 1024 * 1024) (10 * 1024 * 1024);
|
||||
nr_tests = %d;
|
||||
" (500 * 1024 * 1024) (50 * 1024 * 1024) (10 * 1024 * 1024) nr_tests;
|
||||
|
||||
iteri (
|
||||
fun i test_name ->
|
||||
pr " printf (\"%3d/%3d %s\\n\");\n" (i+1) nr_tests test_name;
|
||||
pr " printf (\"%3d/%%3d %s\\n\", nr_tests);\n" (i+1) test_name;
|
||||
pr " if (%s () == -1) {\n" test_name;
|
||||
pr " printf (\"%s FAILED\\n\");\n" test_name;
|
||||
pr " failed++;\n";
|
||||
@@ -2284,8 +2418,7 @@ int main (int argc, char *argv[])
|
||||
pr "\n";
|
||||
|
||||
pr " if (failed > 0) {\n";
|
||||
pr " printf (\"***** %%d / %d tests FAILED *****\\n\", failed);\n"
|
||||
nr_tests;
|
||||
pr " printf (\"***** %%d / %%d tests FAILED *****\\n\", failed, nr_tests);\n";
|
||||
pr " exit (1);\n";
|
||||
pr " }\n";
|
||||
pr "\n";
|
||||
@@ -2434,6 +2567,44 @@ and generate_one_test name i (init, test) =
|
||||
in
|
||||
List.iter (generate_test_command_call test_name) seq;
|
||||
generate_test_command_call ~test test_name last
|
||||
| TestOutputStruct (seq, checks) ->
|
||||
pr " /* TestOutputStruct for %s (%d) */\n" name i;
|
||||
let seq, last = get_seq_last seq in
|
||||
let test () =
|
||||
List.iter (
|
||||
function
|
||||
| CompareWithInt (field, expected) ->
|
||||
pr " if (r->%s != %d) {\n" field expected;
|
||||
pr " fprintf (stderr, \"%s: %s was %%d, expected %d\\n\",\n"
|
||||
test_name field expected;
|
||||
pr " (int) r->%s);\n" field;
|
||||
pr " return -1;\n";
|
||||
pr " }\n"
|
||||
| CompareWithString (field, expected) ->
|
||||
pr " if (strcmp (r->%s, \"%s\") != 0) {\n" field expected;
|
||||
pr " fprintf (stderr, \"%s: %s was \"%%s\", expected \"%s\"\\n\",\n"
|
||||
test_name field expected;
|
||||
pr " r->%s);\n" field;
|
||||
pr " return -1;\n";
|
||||
pr " }\n"
|
||||
| CompareFieldsIntEq (field1, field2) ->
|
||||
pr " if (r->%s != r->%s) {\n" field1 field2;
|
||||
pr " fprintf (stderr, \"%s: %s (%%d) <> %s (%%d)\\n\",\n"
|
||||
test_name field1 field2;
|
||||
pr " (int) r->%s, (int) r->%s);\n" field1 field2;
|
||||
pr " return -1;\n";
|
||||
pr " }\n"
|
||||
| CompareFieldsStrEq (field1, field2) ->
|
||||
pr " if (strcmp (r->%s, r->%s) != 0) {\n" field1 field2;
|
||||
pr " fprintf (stderr, \"%s: %s (\"%%s\") <> %s (\"%%s\")\\n\",\n"
|
||||
test_name field1 field2;
|
||||
pr " r->%s, r->%s);\n" field1 field2;
|
||||
pr " return -1;\n";
|
||||
pr " }\n"
|
||||
) checks
|
||||
in
|
||||
List.iter (generate_test_command_call test_name) seq;
|
||||
generate_test_command_call ~test test_name last
|
||||
| TestLastFail seq ->
|
||||
pr " /* TestLastFail for %s (%d) */\n" name i;
|
||||
let seq, last = get_seq_last seq in
|
||||
@@ -2494,17 +2665,17 @@ and generate_test_command_call ?(expect_error = false) ?test test_name cmd =
|
||||
pr " int i;\n";
|
||||
"NULL"
|
||||
| RIntBool _ ->
|
||||
pr " struct guestfs_int_bool *r;\n";
|
||||
"NULL"
|
||||
pr " struct guestfs_int_bool *r;\n"; "NULL"
|
||||
| RPVList _ ->
|
||||
pr " struct guestfs_lvm_pv_list *r;\n";
|
||||
"NULL"
|
||||
pr " struct guestfs_lvm_pv_list *r;\n"; "NULL"
|
||||
| RVGList _ ->
|
||||
pr " struct guestfs_lvm_vg_list *r;\n";
|
||||
"NULL"
|
||||
pr " struct guestfs_lvm_vg_list *r;\n"; "NULL"
|
||||
| RLVList _ ->
|
||||
pr " struct guestfs_lvm_lv_list *r;\n";
|
||||
"NULL" in
|
||||
pr " struct guestfs_lvm_lv_list *r;\n"; "NULL"
|
||||
| RStat _ ->
|
||||
pr " struct guestfs_stat *r;\n"; "NULL"
|
||||
| RStatVFS _ ->
|
||||
pr " struct guestfs_statvfs *r;\n"; "NULL" in
|
||||
|
||||
pr " suppress_error = %d;\n" (if expect_error then 1 else 0);
|
||||
pr " r = guestfs_%s (g" name;
|
||||
@@ -2555,6 +2726,8 @@ and generate_test_command_call ?(expect_error = false) ?test test_name cmd =
|
||||
pr " guestfs_free_lvm_vg_list (r);\n"
|
||||
| RLVList _ ->
|
||||
pr " guestfs_free_lvm_lv_list (r);\n"
|
||||
| RStat _ | RStatVFS _ ->
|
||||
pr " free (r);\n"
|
||||
);
|
||||
|
||||
pr " }\n"
|
||||
@@ -2694,6 +2867,21 @@ and generate_fish_cmds () =
|
||||
pr "\n";
|
||||
) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
|
||||
|
||||
(* print_{stat,statvfs} functions *)
|
||||
List.iter (
|
||||
function
|
||||
| typ, cols ->
|
||||
pr "static void print_%s (struct guestfs_%s *%s)\n" typ typ typ;
|
||||
pr "{\n";
|
||||
List.iter (
|
||||
function
|
||||
| name, `Int ->
|
||||
pr " printf (\"%s: %%\" PRIi64 \"\\n\", %s->%s);\n" name typ name
|
||||
) cols;
|
||||
pr "}\n";
|
||||
pr "\n";
|
||||
) ["stat", stat_cols; "statvfs", statvfs_cols];
|
||||
|
||||
(* run_<action> actions *)
|
||||
List.iter (
|
||||
fun (name, style, _, flags, _, _, _) ->
|
||||
@@ -2710,6 +2898,8 @@ and generate_fish_cmds () =
|
||||
| RPVList _ -> pr " struct guestfs_lvm_pv_list *r;\n"
|
||||
| RVGList _ -> pr " struct guestfs_lvm_vg_list *r;\n"
|
||||
| RLVList _ -> pr " struct guestfs_lvm_lv_list *r;\n"
|
||||
| RStat _ -> pr " struct guestfs_stat *r;\n"
|
||||
| RStatVFS _ -> pr " struct guestfs_statvfs *r;\n"
|
||||
);
|
||||
List.iter (
|
||||
function
|
||||
@@ -2797,6 +2987,16 @@ and generate_fish_cmds () =
|
||||
pr " print_lv_list (r);\n";
|
||||
pr " guestfs_free_lvm_lv_list (r);\n";
|
||||
pr " return 0;\n"
|
||||
| RStat _ ->
|
||||
pr " if (r == NULL) return -1;\n";
|
||||
pr " print_stat (r);\n";
|
||||
pr " free (r);\n";
|
||||
pr " return 0;\n"
|
||||
| RStatVFS _ ->
|
||||
pr " if (r == NULL) return -1;\n";
|
||||
pr " print_statvfs (r);\n";
|
||||
pr " free (r);\n";
|
||||
pr " return 0;\n"
|
||||
);
|
||||
pr "}\n";
|
||||
pr "\n"
|
||||
@@ -2976,6 +3176,12 @@ and generate_prototype ?(extern = true) ?(static = false) ?(semicolon = true)
|
||||
| RLVList _ ->
|
||||
if not in_daemon then pr "struct guestfs_lvm_lv_list *"
|
||||
else pr "guestfs_lvm_int_lv_list *"
|
||||
| RStat _ ->
|
||||
if not in_daemon then pr "struct guestfs_stat *"
|
||||
else pr "guestfs_int_stat *"
|
||||
| RStatVFS _ ->
|
||||
if not in_daemon then pr "struct guestfs_statvfs *"
|
||||
else pr "guestfs_int_statvfs *"
|
||||
);
|
||||
pr "%s%s (" prefix name;
|
||||
if handle = None && List.length (snd style) = 0 then
|
||||
@@ -3051,6 +3257,8 @@ val close : t -> unit
|
||||
";
|
||||
generate_ocaml_lvm_structure_decls ();
|
||||
|
||||
generate_ocaml_stat_structure_decls ();
|
||||
|
||||
(* The actions. *)
|
||||
List.iter (
|
||||
fun (name, style, _, _, _, shortdesc, _) ->
|
||||
@@ -3076,6 +3284,8 @@ let () =
|
||||
|
||||
generate_ocaml_lvm_structure_decls ();
|
||||
|
||||
generate_ocaml_stat_structure_decls ();
|
||||
|
||||
(* The actions. *)
|
||||
List.iter (
|
||||
fun (name, style, _, _, _, shortdesc, _) ->
|
||||
@@ -3166,6 +3376,30 @@ and generate_ocaml_c () =
|
||||
pr "\n";
|
||||
) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
|
||||
|
||||
(* Stat copy functions. *)
|
||||
List.iter (
|
||||
fun (typ, cols) ->
|
||||
pr "static CAMLprim value\n";
|
||||
pr "copy_%s (const struct guestfs_%s *%s)\n" typ typ typ;
|
||||
pr "{\n";
|
||||
pr " CAMLparam0 ();\n";
|
||||
pr " CAMLlocal2 (rv, v);\n";
|
||||
pr "\n";
|
||||
pr " rv = caml_alloc (%d, 0);\n" (List.length cols);
|
||||
iteri (
|
||||
fun i col ->
|
||||
(match col with
|
||||
| name, `Int ->
|
||||
pr " v = caml_copy_int64 (%s->%s);\n" typ name
|
||||
);
|
||||
pr " Store_field (rv, %d, v);\n" i
|
||||
) cols;
|
||||
pr " CAMLreturn (rv);\n";
|
||||
pr "}\n";
|
||||
pr "\n";
|
||||
) ["stat", stat_cols; "statvfs", statvfs_cols];
|
||||
|
||||
(* The wrappers. *)
|
||||
List.iter (
|
||||
fun (name, style, _, _, _, _, _) ->
|
||||
let params =
|
||||
@@ -3220,17 +3454,17 @@ and generate_ocaml_c () =
|
||||
pr " char **r;\n";
|
||||
"NULL"
|
||||
| RIntBool _ ->
|
||||
pr " struct guestfs_int_bool *r;\n";
|
||||
"NULL"
|
||||
pr " struct guestfs_int_bool *r;\n"; "NULL"
|
||||
| RPVList _ ->
|
||||
pr " struct guestfs_lvm_pv_list *r;\n";
|
||||
"NULL"
|
||||
pr " struct guestfs_lvm_pv_list *r;\n"; "NULL"
|
||||
| RVGList _ ->
|
||||
pr " struct guestfs_lvm_vg_list *r;\n";
|
||||
"NULL"
|
||||
pr " struct guestfs_lvm_vg_list *r;\n"; "NULL"
|
||||
| RLVList _ ->
|
||||
pr " struct guestfs_lvm_lv_list *r;\n";
|
||||
"NULL" in
|
||||
pr " struct guestfs_lvm_lv_list *r;\n"; "NULL"
|
||||
| RStat _ ->
|
||||
pr " struct guestfs_stat *r;\n"; "NULL"
|
||||
| RStatVFS _ ->
|
||||
pr " struct guestfs_statvfs *r;\n"; "NULL" in
|
||||
pr "\n";
|
||||
|
||||
pr " caml_enter_blocking_section ();\n";
|
||||
@@ -3276,6 +3510,12 @@ and generate_ocaml_c () =
|
||||
| RLVList _ ->
|
||||
pr " rv = copy_lvm_lv_list (r);\n";
|
||||
pr " guestfs_free_lvm_lv_list (r);\n";
|
||||
| RStat _ ->
|
||||
pr " rv = copy_stat (r);\n";
|
||||
pr " free (r);\n";
|
||||
| RStatVFS _ ->
|
||||
pr " rv = copy_statvfs (r);\n";
|
||||
pr " free (r);\n";
|
||||
);
|
||||
|
||||
pr " CAMLreturn (rv);\n";
|
||||
@@ -3310,6 +3550,18 @@ and generate_ocaml_lvm_structure_decls () =
|
||||
pr "\n"
|
||||
) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols]
|
||||
|
||||
and generate_ocaml_stat_structure_decls () =
|
||||
List.iter (
|
||||
fun (typ, cols) ->
|
||||
pr "type %s = {\n" typ;
|
||||
List.iter (
|
||||
function
|
||||
| name, `Int -> pr " %s : int64;\n" name
|
||||
) cols;
|
||||
pr "}\n";
|
||||
pr "\n"
|
||||
) ["stat", stat_cols; "statvfs", statvfs_cols]
|
||||
|
||||
and generate_ocaml_prototype ?(is_external = false) name style =
|
||||
if is_external then pr "external " else pr "val ";
|
||||
pr "%s : t -> " name;
|
||||
@@ -3332,6 +3584,8 @@ and generate_ocaml_prototype ?(is_external = false) name style =
|
||||
| RPVList _ -> pr "lvm_pv array"
|
||||
| RVGList _ -> pr "lvm_vg array"
|
||||
| RLVList _ -> pr "lvm_lv array"
|
||||
| RStat _ -> pr "stat"
|
||||
| RStatVFS _ -> pr "statvfs"
|
||||
);
|
||||
if is_external then (
|
||||
pr " = ";
|
||||
@@ -3442,7 +3696,8 @@ DESTROY (g)
|
||||
| RString _ -> pr "SV *\n"
|
||||
| RStringList _
|
||||
| RIntBool _
|
||||
| RPVList _ | RVGList _ | RLVList _ ->
|
||||
| RPVList _ | RVGList _ | RLVList _
|
||||
| RStat _ | RStatVFS _ ->
|
||||
pr "void\n" (* all lists returned implictly on the stack *)
|
||||
);
|
||||
(* Call and arguments. *)
|
||||
@@ -3556,11 +3811,16 @@ DESTROY (g)
|
||||
pr " PUSHs (sv_2mortal (newSViv (r->b)));\n";
|
||||
pr " guestfs_free_int_bool (r);\n";
|
||||
| RPVList n ->
|
||||
generate_perl_lvm_code "pv" pv_cols name style n do_cleanups;
|
||||
generate_perl_lvm_code "pv" pv_cols name style n do_cleanups
|
||||
| RVGList n ->
|
||||
generate_perl_lvm_code "vg" vg_cols name style n do_cleanups;
|
||||
generate_perl_lvm_code "vg" vg_cols name style n do_cleanups
|
||||
| RLVList n ->
|
||||
generate_perl_lvm_code "lv" lv_cols name style n do_cleanups;
|
||||
generate_perl_lvm_code "lv" lv_cols name style n do_cleanups
|
||||
| RStat n ->
|
||||
generate_perl_stat_code "stat" stat_cols name style n do_cleanups
|
||||
| RStatVFS n ->
|
||||
generate_perl_stat_code
|
||||
"statvfs" statvfs_cols name style n do_cleanups
|
||||
);
|
||||
|
||||
pr "\n"
|
||||
@@ -3603,6 +3863,24 @@ and generate_perl_lvm_code typ cols name style n do_cleanups =
|
||||
pr " }\n";
|
||||
pr " guestfs_free_lvm_%s_list (%s);\n" typ n
|
||||
|
||||
and generate_perl_stat_code typ cols name style n do_cleanups =
|
||||
pr "PREINIT:\n";
|
||||
pr " struct guestfs_%s *%s;\n" typ n;
|
||||
pr " PPCODE:\n";
|
||||
pr " %s = guestfs_%s " n name;
|
||||
generate_call_args ~handle:"g" style;
|
||||
pr ";\n";
|
||||
do_cleanups ();
|
||||
pr " if (%s == NULL)\n" n;
|
||||
pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
|
||||
pr " EXTEND (SP, %d);\n" (List.length cols);
|
||||
List.iter (
|
||||
function
|
||||
| name, `Int ->
|
||||
pr " PUSHs (sv_2mortal (my_newSVll (%s->%s)));\n" n name
|
||||
) cols;
|
||||
pr " free (%s);\n" n
|
||||
|
||||
(* Generate Sys/Guestfs.pm. *)
|
||||
and generate_perl_pm () =
|
||||
generate_header HashStyle LGPLv2;
|
||||
@@ -3734,6 +4012,8 @@ and generate_perl_prototype name style =
|
||||
| RPVList n
|
||||
| RVGList n
|
||||
| RLVList n -> pr "@%s = " n
|
||||
| RStat n
|
||||
| RStatVFS n -> pr "%%%s = " n
|
||||
);
|
||||
pr "$h->%s (" name;
|
||||
let comma = ref false in
|
||||
@@ -3925,6 +4205,27 @@ py_guestfs_close (PyObject *self, PyObject *args)
|
||||
pr "\n"
|
||||
) ["pv", pv_cols; "vg", vg_cols; "lv", lv_cols];
|
||||
|
||||
(* Stat structures, turned into Python dictionaries. *)
|
||||
List.iter (
|
||||
fun (typ, cols) ->
|
||||
pr "static PyObject *\n";
|
||||
pr "put_%s (struct guestfs_%s *%s)\n" typ typ typ;
|
||||
pr "{\n";
|
||||
pr " PyObject *dict;\n";
|
||||
pr "\n";
|
||||
pr " dict = PyDict_New ();\n";
|
||||
List.iter (
|
||||
function
|
||||
| name, `Int ->
|
||||
pr " PyDict_SetItemString (dict, \"%s\",\n" name;
|
||||
pr " PyLong_FromLongLong (%s->%s));\n"
|
||||
typ name
|
||||
) cols;
|
||||
pr " return dict;\n";
|
||||
pr "};\n";
|
||||
pr "\n";
|
||||
) ["stat", stat_cols; "statvfs", statvfs_cols];
|
||||
|
||||
(* Python wrapper functions. *)
|
||||
List.iter (
|
||||
fun (name, style, _, _, _, _, _) ->
|
||||
@@ -3945,7 +4246,9 @@ py_guestfs_close (PyObject *self, PyObject *args)
|
||||
| RIntBool _ -> pr " struct guestfs_int_bool *r;\n"; "NULL"
|
||||
| RPVList n -> pr " struct guestfs_lvm_pv_list *r;\n"; "NULL"
|
||||
| RVGList n -> pr " struct guestfs_lvm_vg_list *r;\n"; "NULL"
|
||||
| RLVList n -> pr " struct guestfs_lvm_lv_list *r;\n"; "NULL" in
|
||||
| RLVList n -> pr " struct guestfs_lvm_lv_list *r;\n"; "NULL"
|
||||
| RStat n -> pr " struct guestfs_stat *r;\n"; "NULL"
|
||||
| RStatVFS n -> pr " struct guestfs_statvfs *r;\n"; "NULL" in
|
||||
|
||||
List.iter (
|
||||
function
|
||||
@@ -4039,6 +4342,12 @@ py_guestfs_close (PyObject *self, PyObject *args)
|
||||
| RLVList n ->
|
||||
pr " py_r = put_lvm_lv_list (r);\n";
|
||||
pr " guestfs_free_lvm_lv_list (r);\n"
|
||||
| RStat n ->
|
||||
pr " py_r = put_stat (r);\n";
|
||||
pr " free (r);\n"
|
||||
| RStatVFS n ->
|
||||
pr " py_r = put_statvfs (r);\n";
|
||||
pr " free (r);\n"
|
||||
);
|
||||
|
||||
pr " return py_r;\n";
|
||||
|
||||
Reference in New Issue
Block a user