X-Git-Url: http://git.annexia.org/?a=blobdiff_plain;f=src%2Fgenerator.ml;h=bdd032c8279e7d43f86d355fdb03ab27a75c161f;hb=28bce4792198bc832e6ac0027a57091daa4c91c7;hp=a89886f7a39ca77284502f45ad27facbf1b285f7;hpb=bb07a7f858da5d07c57360e62c0ddfd24ce6be45;p=libguestfs.git diff --git a/src/generator.ml b/src/generator.ml index a89886f..bdd032c 100755 --- a/src/generator.ml +++ b/src/generator.ml @@ -380,6 +380,25 @@ This returns the current state as an opaque integer. This is only useful for printing debug and internal error messages. For more information on states, see L."); + + ("set_busy", (RErr, []), -1, [NotInFish], + [], + "set state to busy", + "\ +This sets the state to C. This is only used when implementing +actions using the low-level API. + +For more information on states, see L."); + + ("set_ready", (RErr, []), -1, [NotInFish], + [], + "set state to ready", + "\ +This sets the state to C. This is only used when implementing +actions using the low-level API. + +For more information on states, see L."); + ] let daemon_functions = [ @@ -1254,7 +1273,10 @@ Reread the partition table on C. This uses the L command."); ("upload", (RErr, [FileIn "filename"; String "remotefilename"]), 66, [], - [], + [InitBasicFS, TestOutput ( + (* Pick a file from cwd which isn't likely to change. *) + [["upload"; "COPYING.LIB"; "/COPYING.LIB"]; + ["checksum"; "md5"; "/COPYING.LIB"]], "e3eda01d9815f8d24aae2dbd89b68b06")], "upload a file from the local machine", "\ Upload local file C to C on the @@ -1265,7 +1287,12 @@ C can also be a named pipe. See also C."); ("download", (RErr, [String "remotefilename"; FileOut "filename"]), 67, [], - [], + [InitBasicFS, TestOutput ( + (* Pick a file from cwd which isn't likely to change. *) + [["upload"; "COPYING.LIB"; "/COPYING.LIB"]; + ["download"; "/COPYING.LIB"; "testdownload.tmp"]; + ["upload"; "testdownload.tmp"; "/upload"]; + ["checksum"; "md5"; "/upload"]], "e3eda01d9815f8d24aae2dbd89b68b06")], "download a file to the local machine", "\ Download file C and save it as C @@ -1275,6 +1302,113 @@ C can also be a named pipe. See also C, C."); + ("checksum", (RString "checksum", [String "csumtype"; String "path"]), 68, [], + [InitBasicFS, TestOutput ( + [["write_file"; "/new"; "test\n"; "0"]; + ["checksum"; "crc"; "/new"]], "935282863"); + InitBasicFS, TestLastFail ( + [["checksum"; "crc"; "/new"]]); + InitBasicFS, TestOutput ( + [["write_file"; "/new"; "test\n"; "0"]; + ["checksum"; "md5"; "/new"]], "d8e8fca2dc0f896fd7cb4cb0031ba249"); + InitBasicFS, TestOutput ( + [["write_file"; "/new"; "test\n"; "0"]; + ["checksum"; "sha1"; "/new"]], "4e1243bd22c66e76c2ba9eddc1f91394e57f9f83"); + InitBasicFS, TestOutput ( + [["write_file"; "/new"; "test\n"; "0"]; + ["checksum"; "sha224"; "/new"]], "52f1bf093f4b7588726035c176c0cdb4376cfea53819f1395ac9e6ec"); + InitBasicFS, TestOutput ( + [["write_file"; "/new"; "test\n"; "0"]; + ["checksum"; "sha256"; "/new"]], "f2ca1bb6c7e907d06dafe4687e579fce76b37e4e93b7605022da52e6ccc26fd2"); + InitBasicFS, TestOutput ( + [["write_file"; "/new"; "test\n"; "0"]; + ["checksum"; "sha384"; "/new"]], "109bb6b5b6d5547c1ce03c7a8bd7d8f80c1cb0957f50c4f7fda04692079917e4f9cad52b878f3d8234e1a170b154b72d"); + InitBasicFS, TestOutput ( + [["write_file"; "/new"; "test\n"; "0"]; + ["checksum"; "sha512"; "/new"]], "0e3e75234abc68f4378a86b3f4b32a198ba301845b0cd6e50106e874345700cc6663a86c1ea125dc5e92be17c98f9a0f85ca9d5f595db2012f7cc3571945c123")], + "compute MD5, SHAx or CRC checksum of file", + "\ +This call computes the MD5, SHAx or CRC checksum of the +file named C. + +The type of checksum to compute is given by the C +parameter which must have one of the following values: + +=over 4 + +=item C + +Compute the cyclic redundancy check (CRC) specified by POSIX +for the C command. + +=item C + +Compute the MD5 hash (using the C program). + +=item C + +Compute the SHA1 hash (using the C program). + +=item C + +Compute the SHA224 hash (using the C program). + +=item C + +Compute the SHA256 hash (using the C program). + +=item C + +Compute the SHA384 hash (using the C program). + +=item C + +Compute the SHA512 hash (using the C program). + +=back + +The checksum is returned as a printable string."); + + ("tar_in", (RErr, [FileIn "tarfile"; String "directory"]), 69, [], + [InitBasicFS, TestOutput ( + [["tar_in"; "images/helloworld.tar"; "/"]; + ["cat"; "/hello"]], "hello\n")], + "unpack tarfile to directory", + "\ +This command uploads and unpacks local file C (an +I tar file) into C. + +To upload a compressed tarball, use C."); + + ("tar_out", (RErr, [String "directory"; FileOut "tarfile"]), 70, [], + [], + "pack directory into tarfile", + "\ +This command packs the contents of C and downloads +it to local file C. + +To download a compressed tarball, use C."); + + ("tgz_in", (RErr, [FileIn "tarball"; String "directory"]), 71, [], + [InitBasicFS, TestOutput ( + [["tgz_in"; "images/helloworld.tar.gz"; "/"]; + ["cat"; "/hello"]], "hello\n")], + "unpack compressed tarball to directory", + "\ +This command uploads and unpacks local file C (a +I tar file) into C. + +To upload an uncompressed tarball, use C."); + + ("tgz_out", (RErr, [String "directory"; FileOut "tarball"]), 72, [], + [], + "pack directory into compressed tarball", + "\ +This command packs the contents of C and downloads +it to local file C. + +To download an uncompressed tarball, use C."); + ] let all_functions = non_daemon_functions @ daemon_functions @@ -1924,9 +2058,17 @@ and generate_xdr () = (* Message header, etc. *) pr "\ +/* The communication protocol is now documented in the guestfs(3) + * manpage. + */ + const GUESTFS_PROGRAM = 0x2000F5F5; const GUESTFS_PROTOCOL_VERSION = 1; +/* These constants must be larger than any possible message length. */ +const GUESTFS_LAUNCH_FLAG = 0xf5f55ff5; +const GUESTFS_CANCEL_FLAG = 0xffffeeee; + enum guestfs_message_direction { GUESTFS_DIRECTION_CALL = 0, /* client -> daemon */ GUESTFS_DIRECTION_REPLY = 1 /* daemon -> client */ @@ -1943,19 +2085,6 @@ struct guestfs_message_error { string error_message; }; -/* For normal requests and replies (not involving any FileIn or - * FileOut parameters), the protocol is: - * - * For requests: - * total length (header + args, but not including length word itself) - * header - * guestfs_foo_args struct - * For replies: - * total length (as above) - * header - * guestfs_foo_ret struct - */ - struct guestfs_message_header { unsigned prog; /* GUESTFS_PROGRAM */ unsigned vers; /* GUESTFS_PROTOCOL_VERSION */ @@ -1965,23 +2094,6 @@ struct guestfs_message_header { guestfs_message_status status; }; -/* Chunked encoding used to transfer files, for FileIn and FileOut - * parameters. - * - * For requests which have >= 1 FileIn parameter: - * length of header + args (but not length word itself, and not chunks) - * header - * guestfs_foo_args struct - * sequence of chunks for FileIn param #0 - * sequence of chunks for FileIn param #1 etc - * - * For replies which have >= 1 FileOut parameter: - * length of header + ret (but not length word itself, and not chunks) - * header - * guestfs_foo_ret struct - * sequence of chunks for FileOut param #0 - * sequence of chunks for FileOut param #1 etc - */ const GUESTFS_MAX_CHUNK_SIZE = 8192; struct guestfs_chunk { @@ -2164,23 +2276,14 @@ check_state (guestfs_h *g, const char *caller) pr "};\n"; pr "\n"; - (* Generate the send callback function. *) - pr "static void %s_send_cb (guestfs_h *g, void *data)\n" shortname; - pr "{\n"; - pr " guestfs_main_loop *ml = guestfs_get_main_loop (g);\n"; - pr " struct %s_ctx *ctx = (struct %s_ctx *) data;\n" shortname shortname; - pr "\n"; - pr " ctx->cb_sequence = 1;\n"; - pr " ml->main_loop_quit (ml, g);\n"; - pr "}\n"; - pr "\n"; - (* Generate the reply callback function. *) pr "static void %s_reply_cb (guestfs_h *g, void *data, XDR *xdr)\n" shortname; pr "{\n"; pr " guestfs_main_loop *ml = guestfs_get_main_loop (g);\n"; pr " struct %s_ctx *ctx = (struct %s_ctx *) data;\n" shortname shortname; pr "\n"; + pr " ml->main_loop_quit (ml, g);\n"; + pr "\n"; pr " if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {\n"; pr " error (g, \"%%s: failed to parse reply header\", \"%s\");\n" name; pr " return;\n"; @@ -2212,7 +2315,6 @@ check_state (guestfs_h *g, const char *caller) pr " done:\n"; pr " ctx->cb_sequence = 1001;\n"; - pr " ml->main_loop_quit (ml, g);\n"; pr "}\n\n"; (* Generate the action stub. *) @@ -2242,14 +2344,15 @@ check_state (guestfs_h *g, const char *caller) pr " int serial;\n"; pr "\n"; pr " if (check_state (g, \"%s\") == -1) return %s;\n" name error_code; + pr " guestfs_set_busy (g);\n"; pr "\n"; pr " memset (&ctx, 0, sizeof ctx);\n"; pr "\n"; - (* Dispatch the main header and arguments. *) + (* Send the main header and arguments. *) (match snd style with | [] -> - pr " serial = guestfs__send (g, GUESTFS_PROC_%s, NULL, NULL);\n" + pr " serial = guestfs__send_sync (g, GUESTFS_PROC_%s, NULL, NULL);\n" (String.uppercase shortname) | args -> List.iter ( @@ -2267,37 +2370,40 @@ check_state (guestfs_h *g, const char *caller) pr " args.%s = %s;\n" n n | FileIn _ | FileOut _ -> () ) args; - pr " serial = guestfs__send (g, GUESTFS_PROC_%s,\n" + pr " serial = guestfs__send_sync (g, GUESTFS_PROC_%s,\n" (String.uppercase shortname); pr " (xdrproc_t) xdr_%s_args, (char *) &args);\n" name; ); - pr " if (serial == -1)\n"; - pr " return %s;\n" error_code; - pr "\n"; - - (* Send the request. *) - pr " ctx.cb_sequence = 0;\n"; - pr " guestfs_set_send_callback (g, %s_send_cb, &ctx);\n" shortname; - pr " (void) ml->main_loop_run (ml, g);\n"; - pr " guestfs_set_send_callback (g, NULL, NULL);\n"; - pr " if (ctx.cb_sequence != 1) {\n"; - pr " error (g, \"%%s send failed, see earlier error messages\", \"%s\");\n" name; + pr " if (serial == -1) {\n"; + pr " guestfs_set_ready (g);\n"; pr " return %s;\n" error_code; pr " }\n"; pr "\n"; (* Send any additional files (FileIn) requested. *) + let need_read_reply_label = ref false in List.iter ( function | FileIn n -> - pr " if (guestfs__send_file_sync (ml, g, %s) == -1)\n" n; - pr " return %s;\n" error_code; + pr " {\n"; + pr " int r;\n"; + pr "\n"; + pr " r = guestfs__send_file_sync (g, %s);\n" n; + pr " if (r == -1) {\n"; + pr " guestfs_set_ready (g);\n"; + pr " return %s;\n" error_code; + pr " }\n"; + pr " if (r == -2) /* daemon cancelled */\n"; + pr " goto read_reply;\n"; + need_read_reply_label := true; + pr " }\n"; pr "\n"; | _ -> () ) (snd style); (* Wait for the reply from the remote end. *) + if !need_read_reply_label then pr " read_reply:\n"; pr " guestfs__switch_to_receiving (g);\n"; pr " ctx.cb_sequence = 0;\n"; pr " guestfs_set_reply_callback (g, %s_reply_cb, &ctx);\n" shortname; @@ -2305,17 +2411,21 @@ check_state (guestfs_h *g, const char *caller) pr " guestfs_set_reply_callback (g, NULL, NULL);\n"; pr " if (ctx.cb_sequence != 1001) {\n"; pr " error (g, \"%%s reply failed, see earlier error messages\", \"%s\");\n" name; + pr " guestfs_set_ready (g);\n"; pr " return %s;\n" error_code; pr " }\n"; pr "\n"; - pr " if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_%s, serial) == -1)\n" + pr " if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_%s, serial) == -1) {\n" (String.uppercase shortname); + pr " guestfs_set_ready (g);\n"; pr " return %s;\n" error_code; + pr " }\n"; pr "\n"; pr " if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {\n"; pr " error (g, \"%%s\", ctx.err.error_message);\n"; + pr " guestfs_set_ready (g);\n"; pr " return %s;\n" error_code; pr " }\n"; pr "\n"; @@ -2324,12 +2434,16 @@ check_state (guestfs_h *g, const char *caller) List.iter ( function | FileOut n -> - pr " if (guestfs__receive_file_sync (ml, g, %s) == -1)\n" n; + pr " if (guestfs__receive_file_sync (g, %s) == -1) {\n" n; + pr " guestfs_set_ready (g);\n"; pr " return %s;\n" error_code; + pr " }\n"; pr "\n"; | _ -> () ) (snd style); + pr " guestfs_set_ready (g);\n"; + (match fst style with | RErr -> pr " return 0;\n" | RInt n | RInt64 n | RBool n -> @@ -2782,8 +2896,8 @@ int main (int argc, char *argv[]) char c = 0; int failed = 0; const char *srcdir; + const char *filename; int fd; - char buf[256]; int nr_tests, test_num = 0; no_test_warnings (); @@ -2798,89 +2912,90 @@ int main (int argc, char *argv[]) srcdir = getenv (\"srcdir\"); if (!srcdir) srcdir = \".\"; - guestfs_set_path (g, srcdir); + chdir (srcdir); + guestfs_set_path (g, \".\"); - snprintf (buf, sizeof buf, \"%%s/test1.img\", srcdir); - fd = open (buf, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666); + filename = \"test1.img\"; + fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666); if (fd == -1) { - perror (buf); + perror (filename); exit (1); } if (lseek (fd, %d, SEEK_SET) == -1) { perror (\"lseek\"); close (fd); - unlink (buf); + unlink (filename); exit (1); } if (write (fd, &c, 1) == -1) { perror (\"write\"); close (fd); - unlink (buf); + unlink (filename); exit (1); } if (close (fd) == -1) { - perror (buf); - unlink (buf); + perror (filename); + unlink (filename); exit (1); } - if (guestfs_add_drive (g, buf) == -1) { - printf (\"guestfs_add_drive %%s FAILED\\n\", buf); + if (guestfs_add_drive (g, filename) == -1) { + printf (\"guestfs_add_drive %%s FAILED\\n\", filename); exit (1); } - snprintf (buf, sizeof buf, \"%%s/test2.img\", srcdir); - fd = open (buf, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666); + filename = \"test2.img\"; + fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666); if (fd == -1) { - perror (buf); + perror (filename); exit (1); } if (lseek (fd, %d, SEEK_SET) == -1) { perror (\"lseek\"); close (fd); - unlink (buf); + unlink (filename); exit (1); } if (write (fd, &c, 1) == -1) { perror (\"write\"); close (fd); - unlink (buf); + unlink (filename); exit (1); } if (close (fd) == -1) { - perror (buf); - unlink (buf); + perror (filename); + unlink (filename); exit (1); } - if (guestfs_add_drive (g, buf) == -1) { - printf (\"guestfs_add_drive %%s FAILED\\n\", buf); + if (guestfs_add_drive (g, filename) == -1) { + printf (\"guestfs_add_drive %%s FAILED\\n\", filename); exit (1); } - snprintf (buf, sizeof buf, \"%%s/test3.img\", srcdir); - fd = open (buf, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666); + filename = \"test3.img\"; + fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666); if (fd == -1) { - perror (buf); + perror (filename); exit (1); } if (lseek (fd, %d, SEEK_SET) == -1) { perror (\"lseek\"); close (fd); - unlink (buf); + unlink (filename); exit (1); } if (write (fd, &c, 1) == -1) { perror (\"write\"); close (fd); - unlink (buf); + unlink (filename); exit (1); } if (close (fd) == -1) { - perror (buf); - unlink (buf); + perror (filename); + unlink (filename); exit (1); } - if (guestfs_add_drive (g, buf) == -1) { - printf (\"guestfs_add_drive %%s FAILED\\n\", buf); + if (guestfs_add_drive (g, filename) == -1) { + printf (\"guestfs_add_drive %%s FAILED\\n\", filename); exit (1); } @@ -2909,12 +3024,9 @@ int main (int argc, char *argv[]) pr "\n"; pr " guestfs_close (g);\n"; - pr " snprintf (buf, sizeof buf, \"%%s/test1.img\", srcdir);\n"; - pr " unlink (buf);\n"; - pr " snprintf (buf, sizeof buf, \"%%s/test2.img\", srcdir);\n"; - pr " unlink (buf);\n"; - pr " snprintf (buf, sizeof buf, \"%%s/test3.img\", srcdir);\n"; - pr " unlink (buf);\n"; + pr " unlink (\"test1.img\");\n"; + pr " unlink (\"test2.img\");\n"; + pr " unlink (\"test3.img\");\n"; pr "\n"; pr " if (failed > 0) {\n";