From 0884d8bbae6d76a603ec1385ada2938f88981c5c Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Tue, 30 Jun 2009 13:09:44 +0100 Subject: [PATCH] Generated code for mknod, mkfifo, mknod_b, mknod_c, umask. --- capitests/tests.c | 538 ++++++++++++++++++++++++++++- daemon/actions.h | 5 + daemon/guestfsd.c | 3 + daemon/stubs.c | 157 +++++++++ fish/cmds.c | 127 +++++++ fish/completion.c | 5 + guestfish-actions.pod | 52 +++ guestfs-actions.pod | 77 +++++ haskell/Guestfs.hs | 67 +++- java/com/redhat/et/libguestfs/GuestFS.java | 109 ++++++ java/com_redhat_et_libguestfs_GuestFS.c | 105 ++++++ ocaml/guestfs.ml | 5 + ocaml/guestfs.mli | 15 + ocaml/guestfs_c_actions.c | 125 +++++++ perl/Guestfs.xs | 68 ++++ perl/lib/Sys/Guestfs.pm | 42 +++ python/guestfs-py.c | 139 ++++++++ python/guestfs.py | 49 +++ ruby/ext/guestfs/_guestfs.c | 126 +++++++ src/MAX_PROC_NR | 2 +- src/guestfs-actions.c | 460 ++++++++++++++++++++++++ src/guestfs-actions.h | 5 + src/guestfs_protocol.c | 197 +++++++++++ src/guestfs_protocol.h | 59 +++- src/guestfs_protocol.x | 39 +++ 25 files changed, 2572 insertions(+), 4 deletions(-) diff --git a/capitests/tests.c b/capitests/tests.c index c8686a1..0ae6aa4 100644 --- a/capitests/tests.c +++ b/capitests/tests.c @@ -156,6 +156,512 @@ static void no_test_warnings (void) fprintf (stderr, "warning: \"guestfs_df\" has no tests\n"); fprintf (stderr, "warning: \"guestfs_df_h\" has no tests\n"); fprintf (stderr, "warning: \"guestfs_mount_loop\" has no tests\n"); + fprintf (stderr, "warning: \"guestfs_umask\" has no tests\n"); +} + +static int test_mknod_c_0_skip (void) +{ + const char *str; + + str = getenv ("TEST_ONLY"); + if (str) + return strstr (str, "mknod_c") == NULL; + str = getenv ("SKIP_TEST_MKNOD_C_0"); + if (str && strcmp (str, "1") == 0) return 1; + str = getenv ("SKIP_TEST_MKNOD_C"); + if (str && strcmp (str, "1") == 0) return 1; + return 0; +} + +static int test_mknod_c_0 (void) +{ + if (test_mknod_c_0_skip ()) { + printf ("%s skipped (reason: environment variable set)\n", "test_mknod_c_0"); + return 0; + } + + /* InitBasicFS for test_mknod_c_0: create ext2 on /dev/sda1 */ + { + char device[] = "/dev/sda"; + int r; + suppress_error = 0; + r = guestfs_blockdev_setrw (g, device); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_umount_all (g); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_lvm_remove_all (g); + if (r == -1) + return -1; + } + { + char device[] = "/dev/sda"; + char lines_0[] = ","; + char *lines[] = { + lines_0, + NULL + }; + int r; + suppress_error = 0; + r = guestfs_sfdisk (g, device, 0, 0, 0, lines); + if (r == -1) + return -1; + } + { + char fstype[] = "ext2"; + char device[] = "/dev/sda1"; + int r; + suppress_error = 0; + r = guestfs_mkfs (g, fstype, device); + if (r == -1) + return -1; + } + { + char device[] = "/dev/sda1"; + char mountpoint[] = "/"; + int r; + suppress_error = 0; + r = guestfs_mount (g, device, mountpoint); + if (r == -1) + return -1; + } + /* TestOutputStruct for mknod_c (0) */ + { + char path[] = "/node"; + int r; + suppress_error = 0; + r = guestfs_mknod_c (g, 511, 99, 66, path); + if (r == -1) + return -1; + } + { + char path[] = "/node"; + struct guestfs_stat *r; + suppress_error = 0; + r = guestfs_stat (g, path); + if (r == NULL) + return -1; + if (r->mode != 8685) { + fprintf (stderr, "test_mknod_c_0: mode was %d, expected 8685\n", + (int) r->mode); + return -1; + } + free (r); + } + return 0; +} + +static int test_mknod_b_0_skip (void) +{ + const char *str; + + str = getenv ("TEST_ONLY"); + if (str) + return strstr (str, "mknod_b") == NULL; + str = getenv ("SKIP_TEST_MKNOD_B_0"); + if (str && strcmp (str, "1") == 0) return 1; + str = getenv ("SKIP_TEST_MKNOD_B"); + if (str && strcmp (str, "1") == 0) return 1; + return 0; +} + +static int test_mknod_b_0 (void) +{ + if (test_mknod_b_0_skip ()) { + printf ("%s skipped (reason: environment variable set)\n", "test_mknod_b_0"); + return 0; + } + + /* InitBasicFS for test_mknod_b_0: create ext2 on /dev/sda1 */ + { + char device[] = "/dev/sda"; + int r; + suppress_error = 0; + r = guestfs_blockdev_setrw (g, device); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_umount_all (g); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_lvm_remove_all (g); + if (r == -1) + return -1; + } + { + char device[] = "/dev/sda"; + char lines_0[] = ","; + char *lines[] = { + lines_0, + NULL + }; + int r; + suppress_error = 0; + r = guestfs_sfdisk (g, device, 0, 0, 0, lines); + if (r == -1) + return -1; + } + { + char fstype[] = "ext2"; + char device[] = "/dev/sda1"; + int r; + suppress_error = 0; + r = guestfs_mkfs (g, fstype, device); + if (r == -1) + return -1; + } + { + char device[] = "/dev/sda1"; + char mountpoint[] = "/"; + int r; + suppress_error = 0; + r = guestfs_mount (g, device, mountpoint); + if (r == -1) + return -1; + } + /* TestOutputStruct for mknod_b (0) */ + { + char path[] = "/node"; + int r; + suppress_error = 0; + r = guestfs_mknod_b (g, 511, 99, 66, path); + if (r == -1) + return -1; + } + { + char path[] = "/node"; + struct guestfs_stat *r; + suppress_error = 0; + r = guestfs_stat (g, path); + if (r == NULL) + return -1; + if (r->mode != 25069) { + fprintf (stderr, "test_mknod_b_0: mode was %d, expected 25069\n", + (int) r->mode); + return -1; + } + free (r); + } + return 0; +} + +static int test_mkfifo_0_skip (void) +{ + const char *str; + + str = getenv ("TEST_ONLY"); + if (str) + return strstr (str, "mkfifo") == NULL; + str = getenv ("SKIP_TEST_MKFIFO_0"); + if (str && strcmp (str, "1") == 0) return 1; + str = getenv ("SKIP_TEST_MKFIFO"); + if (str && strcmp (str, "1") == 0) return 1; + return 0; +} + +static int test_mkfifo_0 (void) +{ + if (test_mkfifo_0_skip ()) { + printf ("%s skipped (reason: environment variable set)\n", "test_mkfifo_0"); + return 0; + } + + /* InitBasicFS for test_mkfifo_0: create ext2 on /dev/sda1 */ + { + char device[] = "/dev/sda"; + int r; + suppress_error = 0; + r = guestfs_blockdev_setrw (g, device); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_umount_all (g); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_lvm_remove_all (g); + if (r == -1) + return -1; + } + { + char device[] = "/dev/sda"; + char lines_0[] = ","; + char *lines[] = { + lines_0, + NULL + }; + int r; + suppress_error = 0; + r = guestfs_sfdisk (g, device, 0, 0, 0, lines); + if (r == -1) + return -1; + } + { + char fstype[] = "ext2"; + char device[] = "/dev/sda1"; + int r; + suppress_error = 0; + r = guestfs_mkfs (g, fstype, device); + if (r == -1) + return -1; + } + { + char device[] = "/dev/sda1"; + char mountpoint[] = "/"; + int r; + suppress_error = 0; + r = guestfs_mount (g, device, mountpoint); + if (r == -1) + return -1; + } + /* TestOutputStruct for mkfifo (0) */ + { + char path[] = "/node"; + int r; + suppress_error = 0; + r = guestfs_mkfifo (g, 511, path); + if (r == -1) + return -1; + } + { + char path[] = "/node"; + struct guestfs_stat *r; + suppress_error = 0; + r = guestfs_stat (g, path); + if (r == NULL) + return -1; + if (r->mode != 4589) { + fprintf (stderr, "test_mkfifo_0: mode was %d, expected 4589\n", + (int) r->mode); + return -1; + } + free (r); + } + return 0; +} + +static int test_mknod_0_skip (void) +{ + const char *str; + + str = getenv ("TEST_ONLY"); + if (str) + return strstr (str, "mknod") == NULL; + str = getenv ("SKIP_TEST_MKNOD_0"); + if (str && strcmp (str, "1") == 0) return 1; + str = getenv ("SKIP_TEST_MKNOD"); + if (str && strcmp (str, "1") == 0) return 1; + return 0; +} + +static int test_mknod_0 (void) +{ + if (test_mknod_0_skip ()) { + printf ("%s skipped (reason: environment variable set)\n", "test_mknod_0"); + return 0; + } + + /* InitBasicFS for test_mknod_0: create ext2 on /dev/sda1 */ + { + char device[] = "/dev/sda"; + int r; + suppress_error = 0; + r = guestfs_blockdev_setrw (g, device); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_umount_all (g); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_lvm_remove_all (g); + if (r == -1) + return -1; + } + { + char device[] = "/dev/sda"; + char lines_0[] = ","; + char *lines[] = { + lines_0, + NULL + }; + int r; + suppress_error = 0; + r = guestfs_sfdisk (g, device, 0, 0, 0, lines); + if (r == -1) + return -1; + } + { + char fstype[] = "ext2"; + char device[] = "/dev/sda1"; + int r; + suppress_error = 0; + r = guestfs_mkfs (g, fstype, device); + if (r == -1) + return -1; + } + { + char device[] = "/dev/sda1"; + char mountpoint[] = "/"; + int r; + suppress_error = 0; + r = guestfs_mount (g, device, mountpoint); + if (r == -1) + return -1; + } + /* TestOutputStruct for mknod (0) */ + { + char path[] = "/node"; + int r; + suppress_error = 0; + r = guestfs_mknod (g, 4607, 0, 0, path); + if (r == -1) + return -1; + } + { + char path[] = "/node"; + struct guestfs_stat *r; + suppress_error = 0; + r = guestfs_stat (g, path); + if (r == NULL) + return -1; + if (r->mode != 4589) { + fprintf (stderr, "test_mknod_0: mode was %d, expected 4589\n", + (int) r->mode); + return -1; + } + free (r); + } + return 0; +} + +static int test_mknod_1_skip (void) +{ + const char *str; + + str = getenv ("TEST_ONLY"); + if (str) + return strstr (str, "mknod") == NULL; + str = getenv ("SKIP_TEST_MKNOD_1"); + if (str && strcmp (str, "1") == 0) return 1; + str = getenv ("SKIP_TEST_MKNOD"); + if (str && strcmp (str, "1") == 0) return 1; + return 0; +} + +static int test_mknod_1 (void) +{ + if (test_mknod_1_skip ()) { + printf ("%s skipped (reason: environment variable set)\n", "test_mknod_1"); + return 0; + } + + /* InitBasicFS for test_mknod_1: create ext2 on /dev/sda1 */ + { + char device[] = "/dev/sda"; + int r; + suppress_error = 0; + r = guestfs_blockdev_setrw (g, device); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_umount_all (g); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_lvm_remove_all (g); + if (r == -1) + return -1; + } + { + char device[] = "/dev/sda"; + char lines_0[] = ","; + char *lines[] = { + lines_0, + NULL + }; + int r; + suppress_error = 0; + r = guestfs_sfdisk (g, device, 0, 0, 0, lines); + if (r == -1) + return -1; + } + { + char fstype[] = "ext2"; + char device[] = "/dev/sda1"; + int r; + suppress_error = 0; + r = guestfs_mkfs (g, fstype, device); + if (r == -1) + return -1; + } + { + char device[] = "/dev/sda1"; + char mountpoint[] = "/"; + int r; + suppress_error = 0; + r = guestfs_mount (g, device, mountpoint); + if (r == -1) + return -1; + } + /* TestOutputStruct for mknod (1) */ + { + char path[] = "/node"; + int r; + suppress_error = 0; + r = guestfs_mknod (g, 25087, 66, 99, path); + if (r == -1) + return -1; + } + { + char path[] = "/node"; + struct guestfs_stat *r; + suppress_error = 0; + r = guestfs_stat (g, path); + if (r == NULL) + return -1; + if (r->mode != 25069) { + fprintf (stderr, "test_mknod_1: mode was %d, expected 25069\n", + (int) r->mode); + return -1; + } + free (r); + } + return 0; } static int test_mkswap_U_0_skip (void) @@ -18975,9 +19481,39 @@ int main (int argc, char *argv[]) /* Cancel previous alarm. */ alarm (0); - nr_tests = 169; + nr_tests = 174; test_num++; + printf ("%3d/%3d test_mknod_c_0\n", test_num, nr_tests); + if (test_mknod_c_0 () == -1) { + printf ("test_mknod_c_0 FAILED\n"); + failed++; + } + test_num++; + printf ("%3d/%3d test_mknod_b_0\n", test_num, nr_tests); + if (test_mknod_b_0 () == -1) { + printf ("test_mknod_b_0 FAILED\n"); + failed++; + } + test_num++; + printf ("%3d/%3d test_mkfifo_0\n", test_num, nr_tests); + if (test_mkfifo_0 () == -1) { + printf ("test_mkfifo_0 FAILED\n"); + failed++; + } + test_num++; + printf ("%3d/%3d test_mknod_0\n", test_num, nr_tests); + if (test_mknod_0 () == -1) { + printf ("test_mknod_0 FAILED\n"); + failed++; + } + test_num++; + printf ("%3d/%3d test_mknod_1\n", test_num, nr_tests); + if (test_mknod_1 () == -1) { + printf ("test_mknod_1 FAILED\n"); + failed++; + } + test_num++; printf ("%3d/%3d test_mkswap_U_0\n", test_num, nr_tests); if (test_mkswap_U_0 () == -1) { printf ("test_mkswap_U_0 FAILED\n"); diff --git a/daemon/actions.h b/daemon/actions.h index 3f8b7a8..ad44d53 100644 --- a/daemon/actions.h +++ b/daemon/actions.h @@ -153,3 +153,8 @@ extern int do_mount_loop (char *file, char *mountpoint); extern int do_mkswap (char *device); extern int do_mkswap_L (char *label, char *device); extern int do_mkswap_U (char *uuid, char *device); +extern int do_mknod (int mode, int devmajor, int devminor, char *path); +extern int do_mkfifo (int mode, char *path); +extern int do_mknod_b (int mode, int devmajor, int devminor, char *path); +extern int do_mknod_c (int mode, int devmajor, int devminor, char *path); +extern int do_umask (int mask); diff --git a/daemon/guestfsd.c b/daemon/guestfsd.c index 030aabe..7eabbd4 100644 --- a/daemon/guestfsd.c +++ b/daemon/guestfsd.c @@ -160,6 +160,9 @@ main (int argc, char *argv[]) setenv ("SHELL", "/bin/sh", 1); setenv ("LANG", "C", 1); + /* We document that umask defaults to 022 (it should be this anyway). */ + umask (022); + /* Resolve the hostname. */ memset (&hints, 0, sizeof hints); hints.ai_socktype = SOCK_STREAM; diff --git a/daemon/stubs.c b/daemon/stubs.c index 48f16c2..033f42c 100644 --- a/daemon/stubs.c +++ b/daemon/stubs.c @@ -3335,6 +3335,148 @@ done: xdr_free ((xdrproc_t) xdr_guestfs_mkswap_U_args, (char *) &args); } +static void mknod_stub (XDR *xdr_in) +{ + int r; + struct guestfs_mknod_args args; + int mode; + int devmajor; + int devminor; + char *path; + + memset (&args, 0, sizeof args); + + if (!xdr_guestfs_mknod_args (xdr_in, &args)) { + reply_with_error ("%s: daemon failed to decode procedure arguments", "mknod"); + return; + } + mode = args.mode; + devmajor = args.devmajor; + devminor = args.devminor; + path = args.path; + + r = do_mknod (mode, devmajor, devminor, path); + if (r == -1) + /* do_mknod has already called reply_with_error */ + goto done; + + reply (NULL, NULL); +done: + xdr_free ((xdrproc_t) xdr_guestfs_mknod_args, (char *) &args); +} + +static void mkfifo_stub (XDR *xdr_in) +{ + int r; + struct guestfs_mkfifo_args args; + int mode; + char *path; + + memset (&args, 0, sizeof args); + + if (!xdr_guestfs_mkfifo_args (xdr_in, &args)) { + reply_with_error ("%s: daemon failed to decode procedure arguments", "mkfifo"); + return; + } + mode = args.mode; + path = args.path; + + r = do_mkfifo (mode, path); + if (r == -1) + /* do_mkfifo has already called reply_with_error */ + goto done; + + reply (NULL, NULL); +done: + xdr_free ((xdrproc_t) xdr_guestfs_mkfifo_args, (char *) &args); +} + +static void mknod_b_stub (XDR *xdr_in) +{ + int r; + struct guestfs_mknod_b_args args; + int mode; + int devmajor; + int devminor; + char *path; + + memset (&args, 0, sizeof args); + + if (!xdr_guestfs_mknod_b_args (xdr_in, &args)) { + reply_with_error ("%s: daemon failed to decode procedure arguments", "mknod_b"); + return; + } + mode = args.mode; + devmajor = args.devmajor; + devminor = args.devminor; + path = args.path; + + r = do_mknod_b (mode, devmajor, devminor, path); + if (r == -1) + /* do_mknod_b has already called reply_with_error */ + goto done; + + reply (NULL, NULL); +done: + xdr_free ((xdrproc_t) xdr_guestfs_mknod_b_args, (char *) &args); +} + +static void mknod_c_stub (XDR *xdr_in) +{ + int r; + struct guestfs_mknod_c_args args; + int mode; + int devmajor; + int devminor; + char *path; + + memset (&args, 0, sizeof args); + + if (!xdr_guestfs_mknod_c_args (xdr_in, &args)) { + reply_with_error ("%s: daemon failed to decode procedure arguments", "mknod_c"); + return; + } + mode = args.mode; + devmajor = args.devmajor; + devminor = args.devminor; + path = args.path; + + r = do_mknod_c (mode, devmajor, devminor, path); + if (r == -1) + /* do_mknod_c has already called reply_with_error */ + goto done; + + reply (NULL, NULL); +done: + xdr_free ((xdrproc_t) xdr_guestfs_mknod_c_args, (char *) &args); +} + +static void umask_stub (XDR *xdr_in) +{ + int r; + struct guestfs_umask_args args; + int mask; + + memset (&args, 0, sizeof args); + + if (!xdr_guestfs_umask_args (xdr_in, &args)) { + reply_with_error ("%s: daemon failed to decode procedure arguments", "umask"); + return; + } + mask = args.mask; + + r = do_umask (mask); + if (r == -1) + /* do_umask has already called reply_with_error */ + goto done; + + struct guestfs_umask_ret ret; + ret.oldmask = r; + reply ((xdrproc_t) &xdr_guestfs_umask_ret, (char *) &ret); +done: + xdr_free ((xdrproc_t) xdr_guestfs_umask_args, (char *) &args); +} + void dispatch_incoming_message (XDR *xdr_in) { switch (proc_nr) { @@ -3734,6 +3876,21 @@ void dispatch_incoming_message (XDR *xdr_in) case GUESTFS_PROC_MKSWAP_U: mkswap_U_stub (xdr_in); break; + case GUESTFS_PROC_MKNOD: + mknod_stub (xdr_in); + break; + case GUESTFS_PROC_MKFIFO: + mkfifo_stub (xdr_in); + break; + case GUESTFS_PROC_MKNOD_B: + mknod_b_stub (xdr_in); + break; + case GUESTFS_PROC_MKNOD_C: + mknod_c_stub (xdr_in); + break; + case GUESTFS_PROC_UMASK: + umask_stub (xdr_in); + break; default: reply_with_error ("dispatch_incoming_message: unknown procedure number %d, set LIBGUESTFS_PATH to point to the matching libguestfs appliance directory", proc_nr); } diff --git a/fish/cmds.c b/fish/cmds.c index b2b6513..15df267 100644 --- a/fish/cmds.c +++ b/fish/cmds.c @@ -116,7 +116,11 @@ void list_commands (void) printf ("%-20s %s\n", "mkdir", "create a directory"); printf ("%-20s %s\n", "mkdir-p", "create a directory and parents"); printf ("%-20s %s\n", "mkdtemp", "create a temporary directory"); + printf ("%-20s %s\n", "mkfifo", "make FIFO (named pipe)"); printf ("%-20s %s\n", "mkfs", "make a filesystem"); + printf ("%-20s %s\n", "mknod", "make block, character or FIFO devices"); + printf ("%-20s %s\n", "mknod-b", "make block device node"); + printf ("%-20s %s\n", "mknod-c", "make char device node"); printf ("%-20s %s\n", "mkswap", "create a swap partition"); printf ("%-20s %s\n", "mkswap-L", "create a swap partition with a label"); printf ("%-20s %s\n", "mkswap-U", "create a swap partition with an explicit UUID"); @@ -171,6 +175,7 @@ void list_commands (void) printf ("%-20s %s\n", "tgz-out", "pack directory into compressed tarball"); printf ("%-20s %s\n", "touch", "update file timestamps or create a new file"); printf ("%-20s %s\n", "tune2fs-l", "get ext2/ext3/ext4 superblock details"); + printf ("%-20s %s\n", "umask", "set file mode creation mask (umask)"); printf ("%-20s %s\n", "umount", "unmount a filesystem"); printf ("%-20s %s\n", "umount-all", "unmount all filesystems"); printf ("%-20s %s\n", "upload", "upload a file from the local machine"); @@ -656,6 +661,21 @@ void display_command (const char *cmd) if (strcasecmp (cmd, "mkswap_U") == 0 || strcasecmp (cmd, "mkswap-U") == 0) pod2text ("mkswap-U - create a swap partition with an explicit UUID", " mkswap-U \n\nCreate a swap partition on C with UUID C."); else + if (strcasecmp (cmd, "mknod") == 0) + pod2text ("mknod - make block, character or FIFO devices", " mknod \n\nThis call creates block or character special devices, or\nnamed pipes (FIFOs).\n\nThe C parameter should be the mode, using the standard\nconstants. C and C are the\ndevice major and minor numbers, only used when creating block\nand character special devices."); + else + if (strcasecmp (cmd, "mkfifo") == 0) + pod2text ("mkfifo - make FIFO (named pipe)", " mkfifo \n\nThis call creates a FIFO (named pipe) called C with\nmode C. It is just a convenient wrapper around\nC."); + else + if (strcasecmp (cmd, "mknod_b") == 0 || strcasecmp (cmd, "mknod-b") == 0) + pod2text ("mknod-b - make block device node", " mknod-b \n\nThis call creates a block device node called C with\nmode C and device major/minor C and C.\nIt is just a convenient wrapper around C."); + else + if (strcasecmp (cmd, "mknod_c") == 0 || strcasecmp (cmd, "mknod-c") == 0) + pod2text ("mknod-c - make char device node", " mknod-c \n\nThis call creates a char device node called C with\nmode C and device major/minor C and C.\nIt is just a convenient wrapper around C."); + else + if (strcasecmp (cmd, "umask") == 0) + pod2text ("umask - set file mode creation mask (umask)", " umask \n\nThis function sets the mask used for creating new files and\ndevice nodes to C.\n\nTypical umask values would be C<022> which creates new files\nwith permissions like \"-rw-r--r--\" or \"-rwxr-xr-x\", and\nC<002> which creates new files with permissions like\n\"-rw-rw-r--\" or \"-rwxrwxr-x\".\n\nSee also L, C, C.\n\nThis call returns the previous umask."); + else display_builtin_command (cmd); } @@ -3217,6 +3237,98 @@ static int run_mkswap_U (const char *cmd, int argc, char *argv[]) return r; } +static int run_mknod (const char *cmd, int argc, char *argv[]) +{ + int r; + int mode; + int devmajor; + int devminor; + const char *path; + if (argc != 4) { + fprintf (stderr, "%s should have 4 parameter(s)\n", cmd); + fprintf (stderr, "type 'help %s' for help on %s\n", cmd, cmd); + return -1; + } + mode = atoi (argv[0]); + devmajor = atoi (argv[1]); + devminor = atoi (argv[2]); + path = argv[3]; + r = guestfs_mknod (g, mode, devmajor, devminor, path); + return r; +} + +static int run_mkfifo (const char *cmd, int argc, char *argv[]) +{ + int r; + int mode; + const char *path; + 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; + } + mode = atoi (argv[0]); + path = argv[1]; + r = guestfs_mkfifo (g, mode, path); + return r; +} + +static int run_mknod_b (const char *cmd, int argc, char *argv[]) +{ + int r; + int mode; + int devmajor; + int devminor; + const char *path; + if (argc != 4) { + fprintf (stderr, "%s should have 4 parameter(s)\n", cmd); + fprintf (stderr, "type 'help %s' for help on %s\n", cmd, cmd); + return -1; + } + mode = atoi (argv[0]); + devmajor = atoi (argv[1]); + devminor = atoi (argv[2]); + path = argv[3]; + r = guestfs_mknod_b (g, mode, devmajor, devminor, path); + return r; +} + +static int run_mknod_c (const char *cmd, int argc, char *argv[]) +{ + int r; + int mode; + int devmajor; + int devminor; + const char *path; + if (argc != 4) { + fprintf (stderr, "%s should have 4 parameter(s)\n", cmd); + fprintf (stderr, "type 'help %s' for help on %s\n", cmd, cmd); + return -1; + } + mode = atoi (argv[0]); + devmajor = atoi (argv[1]); + devminor = atoi (argv[2]); + path = argv[3]; + r = guestfs_mknod_c (g, mode, devmajor, devminor, path); + return r; +} + +static int run_umask (const char *cmd, int argc, char *argv[]) +{ + int r; + int mask; + 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; + } + mask = atoi (argv[0]); + r = guestfs_umask (g, mask); + if (r == -1) return -1; + printf ("%d\n", r); + return 0; +} + int run_action (const char *cmd, int argc, char *argv[]) { if (strcasecmp (cmd, "launch") == 0 || strcasecmp (cmd, "run") == 0) @@ -3684,6 +3796,21 @@ int run_action (const char *cmd, int argc, char *argv[]) if (strcasecmp (cmd, "mkswap_U") == 0 || strcasecmp (cmd, "mkswap-U") == 0) return run_mkswap_U (cmd, argc, argv); else + if (strcasecmp (cmd, "mknod") == 0) + return run_mknod (cmd, argc, argv); + else + if (strcasecmp (cmd, "mkfifo") == 0) + return run_mkfifo (cmd, argc, argv); + else + if (strcasecmp (cmd, "mknod_b") == 0 || strcasecmp (cmd, "mknod-b") == 0) + return run_mknod_b (cmd, argc, argv); + else + if (strcasecmp (cmd, "mknod_c") == 0 || strcasecmp (cmd, "mknod-c") == 0) + return run_mknod_c (cmd, argc, argv); + else + if (strcasecmp (cmd, "umask") == 0) + return run_umask (cmd, argc, argv); + else { fprintf (stderr, "%s: unknown command\n", cmd); return -1; diff --git a/fish/completion.c b/fish/completion.c index 3cd133b..2ddae2e 100644 --- a/fish/completion.c +++ b/fish/completion.c @@ -202,6 +202,11 @@ static const char *const commands[] = { "mkswap", "mkswap-L", "mkswap-U", + "mknod", + "mkfifo", + "mknod-b", + "mknod-c", + "umask", NULL }; diff --git a/guestfish-actions.pod b/guestfish-actions.pod index 986284e..8ced2e1 100644 --- a/guestfish-actions.pod +++ b/guestfish-actions.pod @@ -1020,6 +1020,14 @@ directory and its contents after use. See also: L +=head2 mkfifo + + mkfifo mode path + +This call creates a FIFO (named pipe) called C with +mode C. It is just a convenient wrapper around +C. + =head2 mkfs mkfs fstype device @@ -1028,6 +1036,34 @@ This creates a filesystem on C (usually a partition or LVM logical volume). The filesystem type is C, for example C. +=head2 mknod + + mknod mode devmajor devminor path + +This call creates block or character special devices, or +named pipes (FIFOs). + +The C parameter should be the mode, using the standard +constants. C and C are the +device major and minor numbers, only used when creating block +and character special devices. + +=head2 mknod-b + + mknod-b mode devmajor devminor path + +This call creates a block device node called C with +mode C and device major/minor C and C. +It is just a convenient wrapper around C. + +=head2 mknod-c + + mknod-c mode devmajor devminor path + +This call creates a char device node called C with +mode C and device major/minor C and C. +It is just a convenient wrapper around C. + =head2 mkswap mkswap device @@ -1617,6 +1653,22 @@ manpage for more details. The list of fields returned isn't clearly defined, and depends on both the version of C that libguestfs was built against, and the filesystem itself. +=head2 umask + + umask mask + +This function sets the mask used for creating new files and +device nodes to C. + +Typical umask values would be C<022> which creates new files +with permissions like "-rw-r--r--" or "-rwxr-xr-x", and +C<002> which creates new files with permissions like +"-rw-rw-r--" or "-rwxrwxr-x". + +See also L, C, C. + +This call returns the previous umask. + =head2 umount | unmount umount pathordevice diff --git a/guestfs-actions.pod b/guestfs-actions.pod index 1225dcc..50eba95 100644 --- a/guestfs-actions.pod +++ b/guestfs-actions.pod @@ -1335,6 +1335,18 @@ See also: L This function returns a string, or NULL on error. I. +=head2 guestfs_mkfifo + + int guestfs_mkfifo (guestfs_h *handle, + int mode, + const char *path); + +This call creates a FIFO (named pipe) called C with +mode C. It is just a convenient wrapper around +C. + +This function returns 0 on success or -1 on error. + =head2 guestfs_mkfs int guestfs_mkfs (guestfs_h *handle, @@ -1347,6 +1359,52 @@ example C. This function returns 0 on success or -1 on error. +=head2 guestfs_mknod + + int guestfs_mknod (guestfs_h *handle, + int mode, + int devmajor, + int devminor, + const char *path); + +This call creates block or character special devices, or +named pipes (FIFOs). + +The C parameter should be the mode, using the standard +constants. C and C are the +device major and minor numbers, only used when creating block +and character special devices. + +This function returns 0 on success or -1 on error. + +=head2 guestfs_mknod_b + + int guestfs_mknod_b (guestfs_h *handle, + int mode, + int devmajor, + int devminor, + const char *path); + +This call creates a block device node called C with +mode C and device major/minor C and C. +It is just a convenient wrapper around C. + +This function returns 0 on success or -1 on error. + +=head2 guestfs_mknod_c + + int guestfs_mknod_c (guestfs_h *handle, + int mode, + int devmajor, + int devminor, + const char *path); + +This call creates a char device node called C with +mode C and device major/minor C and C. +It is just a convenient wrapper around C. + +This function returns 0 on success or -1 on error. + =head2 guestfs_mkswap int guestfs_mkswap (guestfs_h *handle, @@ -2169,6 +2227,25 @@ The array of strings will always have length C<2n+1>, where C keys and values alternate, followed by the trailing NULL entry. I. +=head2 guestfs_umask + + int guestfs_umask (guestfs_h *handle, + int mask); + +This function sets the mask used for creating new files and +device nodes to C. + +Typical umask values would be C<022> which creates new files +with permissions like "-rw-r--r--" or "-rwxr-xr-x", and +C<002> which creates new files with permissions like +"-rw-rw-r--" or "-rwxrwxr-x". + +See also L, C, C. + +This call returns the previous umask. + +On error this function returns -1. + =head2 guestfs_umount int guestfs_umount (guestfs_h *handle, diff --git a/haskell/Guestfs.hs b/haskell/Guestfs.hs index 3148450..8370651 100644 --- a/haskell/Guestfs.hs +++ b/haskell/Guestfs.hs @@ -126,7 +126,12 @@ module Guestfs ( mount_loop, mkswap, mkswap_L, - mkswap_U + mkswap_U, + mknod, + mkfifo, + mknod_b, + mknod_c, + umask ) where import Foreign import Foreign.C @@ -1413,3 +1418,63 @@ mkswap_U h uuid device = do fail err else return () +foreign import ccall unsafe "guestfs_mknod" c_mknod + :: GuestfsP -> CInt -> CInt -> CInt -> CString -> IO (CInt) + +mknod :: GuestfsH -> Int -> Int -> Int -> String -> IO () +mknod h mode devmajor devminor path = do + r <- withCString path $ \path -> withForeignPtr h (\p -> c_mknod p (fromIntegral mode) (fromIntegral devmajor) (fromIntegral devminor) path) + if (r == -1) + then do + err <- last_error h + fail err + else return () + +foreign import ccall unsafe "guestfs_mkfifo" c_mkfifo + :: GuestfsP -> CInt -> CString -> IO (CInt) + +mkfifo :: GuestfsH -> Int -> String -> IO () +mkfifo h mode path = do + r <- withCString path $ \path -> withForeignPtr h (\p -> c_mkfifo p (fromIntegral mode) path) + if (r == -1) + then do + err <- last_error h + fail err + else return () + +foreign import ccall unsafe "guestfs_mknod_b" c_mknod_b + :: GuestfsP -> CInt -> CInt -> CInt -> CString -> IO (CInt) + +mknod_b :: GuestfsH -> Int -> Int -> Int -> String -> IO () +mknod_b h mode devmajor devminor path = do + r <- withCString path $ \path -> withForeignPtr h (\p -> c_mknod_b p (fromIntegral mode) (fromIntegral devmajor) (fromIntegral devminor) path) + if (r == -1) + then do + err <- last_error h + fail err + else return () + +foreign import ccall unsafe "guestfs_mknod_c" c_mknod_c + :: GuestfsP -> CInt -> CInt -> CInt -> CString -> IO (CInt) + +mknod_c :: GuestfsH -> Int -> Int -> Int -> String -> IO () +mknod_c h mode devmajor devminor path = do + r <- withCString path $ \path -> withForeignPtr h (\p -> c_mknod_c p (fromIntegral mode) (fromIntegral devmajor) (fromIntegral devminor) path) + if (r == -1) + then do + err <- last_error h + fail err + else return () + +foreign import ccall unsafe "guestfs_umask" c_umask + :: GuestfsP -> CInt -> IO (CInt) + +umask :: GuestfsH -> Int -> IO (Int) +umask h mask = do + r <- withForeignPtr h (\p -> c_umask p (fromIntegral mask)) + if (r == -1) + then do + err <- last_error h + fail err + else return (fromIntegral r) + diff --git a/java/com/redhat/et/libguestfs/GuestFS.java b/java/com/redhat/et/libguestfs/GuestFS.java index 1e13b3a..3cb1c7f 100644 --- a/java/com/redhat/et/libguestfs/GuestFS.java +++ b/java/com/redhat/et/libguestfs/GuestFS.java @@ -3941,4 +3941,113 @@ public HashMap test0rhashtableerr () private native void _mkswap_U (long g, String uuid, String device) throws LibGuestFSException; + /** + * make block, character or FIFO devices + *

+ * This call creates block or character special devices, or + * named pipes (FIFOs). + *

+ * The "mode" parameter should be the mode, using the + * standard constants. "devmajor" and "devminor" are the + * device major and minor numbers, only used when creating + * block and character special devices. + *

+ * @throws LibGuestFSException + */ + public void mknod (int mode, int devmajor, int devminor, String path) + throws LibGuestFSException + { + if (g == 0) + throw new LibGuestFSException ("mknod: handle is closed"); + _mknod (g, mode, devmajor, devminor, path); + } + private native void _mknod (long g, int mode, int devmajor, int devminor, String path) + throws LibGuestFSException; + + /** + * make FIFO (named pipe) + *

+ * This call creates a FIFO (named pipe) called "path" with + * mode "mode". It is just a convenient wrapper around + * "g.mknod". + *

+ * @throws LibGuestFSException + */ + public void mkfifo (int mode, String path) + throws LibGuestFSException + { + if (g == 0) + throw new LibGuestFSException ("mkfifo: handle is closed"); + _mkfifo (g, mode, path); + } + private native void _mkfifo (long g, int mode, String path) + throws LibGuestFSException; + + /** + * make block device node + *

+ * This call creates a block device node called "path" with + * mode "mode" and device major/minor "devmajor" and + * "devminor". It is just a convenient wrapper around + * "g.mknod". + *

+ * @throws LibGuestFSException + */ + public void mknod_b (int mode, int devmajor, int devminor, String path) + throws LibGuestFSException + { + if (g == 0) + throw new LibGuestFSException ("mknod_b: handle is closed"); + _mknod_b (g, mode, devmajor, devminor, path); + } + private native void _mknod_b (long g, int mode, int devmajor, int devminor, String path) + throws LibGuestFSException; + + /** + * make char device node + *

+ * This call creates a char device node called "path" with + * mode "mode" and device major/minor "devmajor" and + * "devminor". It is just a convenient wrapper around + * "g.mknod". + *

+ * @throws LibGuestFSException + */ + public void mknod_c (int mode, int devmajor, int devminor, String path) + throws LibGuestFSException + { + if (g == 0) + throw new LibGuestFSException ("mknod_c: handle is closed"); + _mknod_c (g, mode, devmajor, devminor, path); + } + private native void _mknod_c (long g, int mode, int devmajor, int devminor, String path) + throws LibGuestFSException; + + /** + * set file mode creation mask (umask) + *

+ * This function sets the mask used for creating new files + * and device nodes to "mask & 0777". + *

+ * Typical umask values would be 022 which creates new + * files with permissions like "-rw-r--r--" or + * "-rwxr-xr-x", and 002 which creates new files with + * permissions like "-rw-rw-r--" or "-rwxrwxr-x". + *

+ * See also umask(2), "g.mknod", "g.mkdir". + *

+ * This call returns the previous umask. + *

+ * @throws LibGuestFSException + */ + public int umask (int mask) + throws LibGuestFSException + { + if (g == 0) + throw new LibGuestFSException ("umask: handle is closed"); + return _umask (g, mask); + } + private native int _umask (long g, int mask) + throws LibGuestFSException; + } diff --git a/java/com_redhat_et_libguestfs_GuestFS.c b/java/com_redhat_et_libguestfs_GuestFS.c index df16102..91095a4 100644 --- a/java/com_redhat_et_libguestfs_GuestFS.c +++ b/java/com_redhat_et_libguestfs_GuestFS.c @@ -4530,3 +4530,108 @@ Java_com_redhat_et_libguestfs_GuestFS__1mkswap_1U } } +JNIEXPORT void JNICALL +Java_com_redhat_et_libguestfs_GuestFS__1mknod + (JNIEnv *env, jobject obj, jlong jg, jint jmode, jint jdevmajor, jint jdevminor, jstring jpath) +{ + guestfs_h *g = (guestfs_h *) (long) jg; + int r; + int mode; + int devmajor; + int devminor; + const char *path; + + mode = jmode; + devmajor = jdevmajor; + devminor = jdevminor; + path = (*env)->GetStringUTFChars (env, jpath, NULL); + r = guestfs_mknod (g, mode, devmajor, devminor, path); + (*env)->ReleaseStringUTFChars (env, jpath, path); + if (r == -1) { + throw_exception (env, guestfs_last_error (g)); + return ; + } +} + +JNIEXPORT void JNICALL +Java_com_redhat_et_libguestfs_GuestFS__1mkfifo + (JNIEnv *env, jobject obj, jlong jg, jint jmode, jstring jpath) +{ + guestfs_h *g = (guestfs_h *) (long) jg; + int r; + int mode; + const char *path; + + mode = jmode; + path = (*env)->GetStringUTFChars (env, jpath, NULL); + r = guestfs_mkfifo (g, mode, path); + (*env)->ReleaseStringUTFChars (env, jpath, path); + if (r == -1) { + throw_exception (env, guestfs_last_error (g)); + return ; + } +} + +JNIEXPORT void JNICALL +Java_com_redhat_et_libguestfs_GuestFS__1mknod_1b + (JNIEnv *env, jobject obj, jlong jg, jint jmode, jint jdevmajor, jint jdevminor, jstring jpath) +{ + guestfs_h *g = (guestfs_h *) (long) jg; + int r; + int mode; + int devmajor; + int devminor; + const char *path; + + mode = jmode; + devmajor = jdevmajor; + devminor = jdevminor; + path = (*env)->GetStringUTFChars (env, jpath, NULL); + r = guestfs_mknod_b (g, mode, devmajor, devminor, path); + (*env)->ReleaseStringUTFChars (env, jpath, path); + if (r == -1) { + throw_exception (env, guestfs_last_error (g)); + return ; + } +} + +JNIEXPORT void JNICALL +Java_com_redhat_et_libguestfs_GuestFS__1mknod_1c + (JNIEnv *env, jobject obj, jlong jg, jint jmode, jint jdevmajor, jint jdevminor, jstring jpath) +{ + guestfs_h *g = (guestfs_h *) (long) jg; + int r; + int mode; + int devmajor; + int devminor; + const char *path; + + mode = jmode; + devmajor = jdevmajor; + devminor = jdevminor; + path = (*env)->GetStringUTFChars (env, jpath, NULL); + r = guestfs_mknod_c (g, mode, devmajor, devminor, path); + (*env)->ReleaseStringUTFChars (env, jpath, path); + if (r == -1) { + throw_exception (env, guestfs_last_error (g)); + return ; + } +} + +JNIEXPORT jint JNICALL +Java_com_redhat_et_libguestfs_GuestFS__1umask + (JNIEnv *env, jobject obj, jlong jg, jint jmask) +{ + guestfs_h *g = (guestfs_h *) (long) jg; + int r; + int mask; + + mask = jmask; + r = guestfs_umask (g, mask); + if (r == -1) { + throw_exception (env, guestfs_last_error (g)); + return 0; + } + return (jint) r; +} + diff --git a/ocaml/guestfs.ml b/ocaml/guestfs.ml index 027f0e9..0bf458c 100644 --- a/ocaml/guestfs.ml +++ b/ocaml/guestfs.ml @@ -301,3 +301,8 @@ external mount_loop : t -> string -> string -> unit = "ocaml_guestfs_mount_loop" external mkswap : t -> string -> unit = "ocaml_guestfs_mkswap" external mkswap_L : t -> string -> string -> unit = "ocaml_guestfs_mkswap_L" external mkswap_U : t -> string -> string -> unit = "ocaml_guestfs_mkswap_U" +external mknod : t -> int -> int -> int -> string -> unit = "ocaml_guestfs_mknod" +external mkfifo : t -> int -> string -> unit = "ocaml_guestfs_mkfifo" +external mknod_b : t -> int -> int -> int -> string -> unit = "ocaml_guestfs_mknod_b" +external mknod_c : t -> int -> int -> int -> string -> unit = "ocaml_guestfs_mknod_c" +external umask : t -> int -> int = "ocaml_guestfs_umask" diff --git a/ocaml/guestfs.mli b/ocaml/guestfs.mli index ef6a142..5cab588 100644 --- a/ocaml/guestfs.mli +++ b/ocaml/guestfs.mli @@ -682,3 +682,18 @@ val mkswap_L : t -> string -> string -> unit val mkswap_U : t -> string -> string -> unit (** create a swap partition with an explicit UUID *) +val mknod : t -> int -> int -> int -> string -> unit +(** make block, character or FIFO devices *) + +val mkfifo : t -> int -> string -> unit +(** make FIFO (named pipe) *) + +val mknod_b : t -> int -> int -> int -> string -> unit +(** make block device node *) + +val mknod_c : t -> int -> int -> int -> string -> unit +(** make char device node *) + +val umask : t -> int -> int +(** set file mode creation mask (umask) *) + diff --git a/ocaml/guestfs_c_actions.c b/ocaml/guestfs_c_actions.c index 6e937f4..6db7239 100644 --- a/ocaml/guestfs_c_actions.c +++ b/ocaml/guestfs_c_actions.c @@ -4777,3 +4777,128 @@ ocaml_guestfs_mkswap_U (value gv, value uuidv, value devicev) CAMLreturn (rv); } +CAMLprim value +ocaml_guestfs_mknod (value gv, value modev, value devmajorv, value devminorv, value pathv) +{ + CAMLparam5 (gv, modev, devmajorv, devminorv, pathv); + CAMLlocal1 (rv); + + guestfs_h *g = Guestfs_val (gv); + if (g == NULL) + caml_failwith ("mknod: used handle after closing it"); + + int mode = Int_val (modev); + int devmajor = Int_val (devmajorv); + int devminor = Int_val (devminorv); + const char *path = String_val (pathv); + int r; + + caml_enter_blocking_section (); + r = guestfs_mknod (g, mode, devmajor, devminor, path); + caml_leave_blocking_section (); + if (r == -1) + ocaml_guestfs_raise_error (g, "mknod"); + + rv = Val_unit; + CAMLreturn (rv); +} + +CAMLprim value +ocaml_guestfs_mkfifo (value gv, value modev, value pathv) +{ + CAMLparam3 (gv, modev, pathv); + CAMLlocal1 (rv); + + guestfs_h *g = Guestfs_val (gv); + if (g == NULL) + caml_failwith ("mkfifo: used handle after closing it"); + + int mode = Int_val (modev); + const char *path = String_val (pathv); + int r; + + caml_enter_blocking_section (); + r = guestfs_mkfifo (g, mode, path); + caml_leave_blocking_section (); + if (r == -1) + ocaml_guestfs_raise_error (g, "mkfifo"); + + rv = Val_unit; + CAMLreturn (rv); +} + +CAMLprim value +ocaml_guestfs_mknod_b (value gv, value modev, value devmajorv, value devminorv, value pathv) +{ + CAMLparam5 (gv, modev, devmajorv, devminorv, pathv); + CAMLlocal1 (rv); + + guestfs_h *g = Guestfs_val (gv); + if (g == NULL) + caml_failwith ("mknod_b: used handle after closing it"); + + int mode = Int_val (modev); + int devmajor = Int_val (devmajorv); + int devminor = Int_val (devminorv); + const char *path = String_val (pathv); + int r; + + caml_enter_blocking_section (); + r = guestfs_mknod_b (g, mode, devmajor, devminor, path); + caml_leave_blocking_section (); + if (r == -1) + ocaml_guestfs_raise_error (g, "mknod_b"); + + rv = Val_unit; + CAMLreturn (rv); +} + +CAMLprim value +ocaml_guestfs_mknod_c (value gv, value modev, value devmajorv, value devminorv, value pathv) +{ + CAMLparam5 (gv, modev, devmajorv, devminorv, pathv); + CAMLlocal1 (rv); + + guestfs_h *g = Guestfs_val (gv); + if (g == NULL) + caml_failwith ("mknod_c: used handle after closing it"); + + int mode = Int_val (modev); + int devmajor = Int_val (devmajorv); + int devminor = Int_val (devminorv); + const char *path = String_val (pathv); + int r; + + caml_enter_blocking_section (); + r = guestfs_mknod_c (g, mode, devmajor, devminor, path); + caml_leave_blocking_section (); + if (r == -1) + ocaml_guestfs_raise_error (g, "mknod_c"); + + rv = Val_unit; + CAMLreturn (rv); +} + +CAMLprim value +ocaml_guestfs_umask (value gv, value maskv) +{ + CAMLparam2 (gv, maskv); + CAMLlocal1 (rv); + + guestfs_h *g = Guestfs_val (gv); + if (g == NULL) + caml_failwith ("umask: used handle after closing it"); + + int mask = Int_val (maskv); + int r; + + caml_enter_blocking_section (); + r = guestfs_umask (g, mask); + caml_leave_blocking_section (); + if (r == -1) + ocaml_guestfs_raise_error (g, "umask"); + + rv = Val_int (r); + CAMLreturn (rv); +} + diff --git a/perl/Guestfs.xs b/perl/Guestfs.xs index 9c8b459..8f4ab5f 100644 --- a/perl/Guestfs.xs +++ b/perl/Guestfs.xs @@ -2902,3 +2902,71 @@ PREINIT: if (r == -1) croak ("mkswap_U: %s", guestfs_last_error (g)); +void +mknod (g, mode, devmajor, devminor, path) + guestfs_h *g; + int mode; + int devmajor; + int devminor; + char *path; +PREINIT: + int r; + PPCODE: + r = guestfs_mknod (g, mode, devmajor, devminor, path); + if (r == -1) + croak ("mknod: %s", guestfs_last_error (g)); + +void +mkfifo (g, mode, path) + guestfs_h *g; + int mode; + char *path; +PREINIT: + int r; + PPCODE: + r = guestfs_mkfifo (g, mode, path); + if (r == -1) + croak ("mkfifo: %s", guestfs_last_error (g)); + +void +mknod_b (g, mode, devmajor, devminor, path) + guestfs_h *g; + int mode; + int devmajor; + int devminor; + char *path; +PREINIT: + int r; + PPCODE: + r = guestfs_mknod_b (g, mode, devmajor, devminor, path); + if (r == -1) + croak ("mknod_b: %s", guestfs_last_error (g)); + +void +mknod_c (g, mode, devmajor, devminor, path) + guestfs_h *g; + int mode; + int devmajor; + int devminor; + char *path; +PREINIT: + int r; + PPCODE: + r = guestfs_mknod_c (g, mode, devmajor, devminor, path); + if (r == -1) + croak ("mknod_c: %s", guestfs_last_error (g)); + +SV * +umask (g, mask) + guestfs_h *g; + int mask; +PREINIT: + int oldmask; + CODE: + oldmask = guestfs_umask (g, mask); + if (oldmask == -1) + croak ("umask: %s", guestfs_last_error (g)); + RETVAL = newSViv (oldmask); + OUTPUT: + RETVAL + diff --git a/perl/lib/Sys/Guestfs.pm b/perl/lib/Sys/Guestfs.pm index 5f8cef4..083a017 100644 --- a/perl/lib/Sys/Guestfs.pm +++ b/perl/lib/Sys/Guestfs.pm @@ -949,12 +949,40 @@ directory and its contents after use. See also: L +=item $h->mkfifo ($mode, $path); + +This call creates a FIFO (named pipe) called C with +mode C. It is just a convenient wrapper around +C<$h-Emknod>. + =item $h->mkfs ($fstype, $device); This creates a filesystem on C (usually a partition or LVM logical volume). The filesystem type is C, for example C. +=item $h->mknod ($mode, $devmajor, $devminor, $path); + +This call creates block or character special devices, or +named pipes (FIFOs). + +The C parameter should be the mode, using the standard +constants. C and C are the +device major and minor numbers, only used when creating block +and character special devices. + +=item $h->mknod_b ($mode, $devmajor, $devminor, $path); + +This call creates a block device node called C with +mode C and device major/minor C and C. +It is just a convenient wrapper around C<$h-Emknod>. + +=item $h->mknod_c ($mode, $devmajor, $devminor, $path); + +This call creates a char device node called C with +mode C and device major/minor C and C. +It is just a convenient wrapper around C<$h-Emknod>. + =item $h->mkswap ($device); Create a swap partition on C. @@ -1442,6 +1470,20 @@ manpage for more details. The list of fields returned isn't clearly defined, and depends on both the version of C that libguestfs was built against, and the filesystem itself. +=item $oldmask = $h->umask ($mask); + +This function sets the mask used for creating new files and +device nodes to C. + +Typical umask values would be C<022> which creates new files +with permissions like "-rw-r--r--" or "-rwxr-xr-x", and +C<002> which creates new files with permissions like +"-rw-rw-r--" or "-rwxrwxr-x". + +See also L, C<$h-Emknod>, C<$h-Emkdir>. + +This call returns the previous umask. + =item $h->umount ($pathordevice); This unmounts the given filesystem. The filesystem may be diff --git a/python/guestfs-py.c b/python/guestfs-py.c index bf27d0d..98a14a0 100644 --- a/python/guestfs-py.c +++ b/python/guestfs-py.c @@ -5053,6 +5053,140 @@ py_guestfs_mkswap_U (PyObject *self, PyObject *args) return py_r; } +static PyObject * +py_guestfs_mknod (PyObject *self, PyObject *args) +{ + PyObject *py_g; + guestfs_h *g; + PyObject *py_r; + int r; + int mode; + int devmajor; + int devminor; + const char *path; + + if (!PyArg_ParseTuple (args, (char *) "Oiiis:guestfs_mknod", + &py_g, &mode, &devmajor, &devminor, &path)) + return NULL; + g = get_handle (py_g); + + r = guestfs_mknod (g, mode, devmajor, devminor, path); + if (r == -1) { + PyErr_SetString (PyExc_RuntimeError, guestfs_last_error (g)); + return NULL; + } + + Py_INCREF (Py_None); + py_r = Py_None; + return py_r; +} + +static PyObject * +py_guestfs_mkfifo (PyObject *self, PyObject *args) +{ + PyObject *py_g; + guestfs_h *g; + PyObject *py_r; + int r; + int mode; + const char *path; + + if (!PyArg_ParseTuple (args, (char *) "Ois:guestfs_mkfifo", + &py_g, &mode, &path)) + return NULL; + g = get_handle (py_g); + + r = guestfs_mkfifo (g, mode, path); + if (r == -1) { + PyErr_SetString (PyExc_RuntimeError, guestfs_last_error (g)); + return NULL; + } + + Py_INCREF (Py_None); + py_r = Py_None; + return py_r; +} + +static PyObject * +py_guestfs_mknod_b (PyObject *self, PyObject *args) +{ + PyObject *py_g; + guestfs_h *g; + PyObject *py_r; + int r; + int mode; + int devmajor; + int devminor; + const char *path; + + if (!PyArg_ParseTuple (args, (char *) "Oiiis:guestfs_mknod_b", + &py_g, &mode, &devmajor, &devminor, &path)) + return NULL; + g = get_handle (py_g); + + r = guestfs_mknod_b (g, mode, devmajor, devminor, path); + if (r == -1) { + PyErr_SetString (PyExc_RuntimeError, guestfs_last_error (g)); + return NULL; + } + + Py_INCREF (Py_None); + py_r = Py_None; + return py_r; +} + +static PyObject * +py_guestfs_mknod_c (PyObject *self, PyObject *args) +{ + PyObject *py_g; + guestfs_h *g; + PyObject *py_r; + int r; + int mode; + int devmajor; + int devminor; + const char *path; + + if (!PyArg_ParseTuple (args, (char *) "Oiiis:guestfs_mknod_c", + &py_g, &mode, &devmajor, &devminor, &path)) + return NULL; + g = get_handle (py_g); + + r = guestfs_mknod_c (g, mode, devmajor, devminor, path); + if (r == -1) { + PyErr_SetString (PyExc_RuntimeError, guestfs_last_error (g)); + return NULL; + } + + Py_INCREF (Py_None); + py_r = Py_None; + return py_r; +} + +static PyObject * +py_guestfs_umask (PyObject *self, PyObject *args) +{ + PyObject *py_g; + guestfs_h *g; + PyObject *py_r; + int r; + int mask; + + if (!PyArg_ParseTuple (args, (char *) "Oi:guestfs_umask", + &py_g, &mask)) + return NULL; + g = get_handle (py_g); + + r = guestfs_umask (g, mask); + if (r == -1) { + PyErr_SetString (PyExc_RuntimeError, guestfs_last_error (g)); + return NULL; + } + + py_r = PyInt_FromLong ((long) r); + return py_r; +} + static PyMethodDef methods[] = { { (char *) "create", py_guestfs_create, METH_VARARGS, NULL }, { (char *) "close", py_guestfs_close, METH_VARARGS, NULL }, @@ -5242,6 +5376,11 @@ static PyMethodDef methods[] = { { (char *) "mkswap", py_guestfs_mkswap, METH_VARARGS, NULL }, { (char *) "mkswap_L", py_guestfs_mkswap_L, METH_VARARGS, NULL }, { (char *) "mkswap_U", py_guestfs_mkswap_U, METH_VARARGS, NULL }, + { (char *) "mknod", py_guestfs_mknod, METH_VARARGS, NULL }, + { (char *) "mkfifo", py_guestfs_mkfifo, METH_VARARGS, NULL }, + { (char *) "mknod_b", py_guestfs_mknod_b, METH_VARARGS, NULL }, + { (char *) "mknod_c", py_guestfs_mknod_c, METH_VARARGS, NULL }, + { (char *) "umask", py_guestfs_umask, METH_VARARGS, NULL }, { NULL, NULL, 0, NULL } }; diff --git a/python/guestfs.py b/python/guestfs.py index d334a91..bb9bc08 100644 --- a/python/guestfs.py +++ b/python/guestfs.py @@ -1905,3 +1905,52 @@ class GuestFS: """ return libguestfsmod.mkswap_U (self._o, uuid, device) + def mknod (self, mode, devmajor, devminor, path): + u"""This call creates block or character special devices, or + named pipes (FIFOs). + + The "mode" parameter should be the mode, using the + standard constants. "devmajor" and "devminor" are the + device major and minor numbers, only used when creating + block and character special devices. + """ + return libguestfsmod.mknod (self._o, mode, devmajor, devminor, path) + + def mkfifo (self, mode, path): + u"""This call creates a FIFO (named pipe) called "path" with + mode "mode". It is just a convenient wrapper around + "g.mknod". + """ + return libguestfsmod.mkfifo (self._o, mode, path) + + def mknod_b (self, mode, devmajor, devminor, path): + u"""This call creates a block device node called "path" with + mode "mode" and device major/minor "devmajor" and + "devminor". It is just a convenient wrapper around + "g.mknod". + """ + return libguestfsmod.mknod_b (self._o, mode, devmajor, devminor, path) + + def mknod_c (self, mode, devmajor, devminor, path): + u"""This call creates a char device node called "path" with + mode "mode" and device major/minor "devmajor" and + "devminor". It is just a convenient wrapper around + "g.mknod". + """ + return libguestfsmod.mknod_c (self._o, mode, devmajor, devminor, path) + + def umask (self, mask): + u"""This function sets the mask used for creating new files + and device nodes to "mask & 0777". + + Typical umask values would be 022 which creates new + files with permissions like "-rw-r--r--" or + "-rwxr-xr-x", and 002 which creates new files with + permissions like "-rw-rw-r--" or "-rwxrwxr-x". + + See also umask(2), "g.mknod", "g.mkdir". + + This call returns the previous umask. + """ + return libguestfsmod.umask (self._o, mask) + diff --git a/ruby/ext/guestfs/_guestfs.c b/ruby/ext/guestfs/_guestfs.c index 9ac8e25..606e9a2 100644 --- a/ruby/ext/guestfs/_guestfs.c +++ b/ruby/ext/guestfs/_guestfs.c @@ -4749,6 +4749,122 @@ static VALUE ruby_guestfs_mkswap_U (VALUE gv, VALUE uuidv, VALUE devicev) return Qnil; } +static VALUE ruby_guestfs_mknod (VALUE gv, VALUE modev, VALUE devmajorv, VALUE devminorv, VALUE pathv) +{ + guestfs_h *g; + Data_Get_Struct (gv, guestfs_h, g); + if (!g) + rb_raise (rb_eArgError, "%s: used handle after closing it", "mknod"); + + int mode = NUM2INT (modev); + int devmajor = NUM2INT (devmajorv); + int devminor = NUM2INT (devminorv); + Check_Type (pathv, T_STRING); + const char *path = StringValueCStr (pathv); + if (!path) + rb_raise (rb_eTypeError, "expected string for parameter %s of %s", + "path", "mknod"); + + int r; + + r = guestfs_mknod (g, mode, devmajor, devminor, path); + if (r == -1) + rb_raise (e_Error, "%s", guestfs_last_error (g)); + + return Qnil; +} + +static VALUE ruby_guestfs_mkfifo (VALUE gv, VALUE modev, VALUE pathv) +{ + guestfs_h *g; + Data_Get_Struct (gv, guestfs_h, g); + if (!g) + rb_raise (rb_eArgError, "%s: used handle after closing it", "mkfifo"); + + int mode = NUM2INT (modev); + Check_Type (pathv, T_STRING); + const char *path = StringValueCStr (pathv); + if (!path) + rb_raise (rb_eTypeError, "expected string for parameter %s of %s", + "path", "mkfifo"); + + int r; + + r = guestfs_mkfifo (g, mode, path); + if (r == -1) + rb_raise (e_Error, "%s", guestfs_last_error (g)); + + return Qnil; +} + +static VALUE ruby_guestfs_mknod_b (VALUE gv, VALUE modev, VALUE devmajorv, VALUE devminorv, VALUE pathv) +{ + guestfs_h *g; + Data_Get_Struct (gv, guestfs_h, g); + if (!g) + rb_raise (rb_eArgError, "%s: used handle after closing it", "mknod_b"); + + int mode = NUM2INT (modev); + int devmajor = NUM2INT (devmajorv); + int devminor = NUM2INT (devminorv); + Check_Type (pathv, T_STRING); + const char *path = StringValueCStr (pathv); + if (!path) + rb_raise (rb_eTypeError, "expected string for parameter %s of %s", + "path", "mknod_b"); + + int r; + + r = guestfs_mknod_b (g, mode, devmajor, devminor, path); + if (r == -1) + rb_raise (e_Error, "%s", guestfs_last_error (g)); + + return Qnil; +} + +static VALUE ruby_guestfs_mknod_c (VALUE gv, VALUE modev, VALUE devmajorv, VALUE devminorv, VALUE pathv) +{ + guestfs_h *g; + Data_Get_Struct (gv, guestfs_h, g); + if (!g) + rb_raise (rb_eArgError, "%s: used handle after closing it", "mknod_c"); + + int mode = NUM2INT (modev); + int devmajor = NUM2INT (devmajorv); + int devminor = NUM2INT (devminorv); + Check_Type (pathv, T_STRING); + const char *path = StringValueCStr (pathv); + if (!path) + rb_raise (rb_eTypeError, "expected string for parameter %s of %s", + "path", "mknod_c"); + + int r; + + r = guestfs_mknod_c (g, mode, devmajor, devminor, path); + if (r == -1) + rb_raise (e_Error, "%s", guestfs_last_error (g)); + + return Qnil; +} + +static VALUE ruby_guestfs_umask (VALUE gv, VALUE maskv) +{ + guestfs_h *g; + Data_Get_Struct (gv, guestfs_h, g); + if (!g) + rb_raise (rb_eArgError, "%s: used handle after closing it", "umask"); + + int mask = NUM2INT (maskv); + + int r; + + r = guestfs_umask (g, mask); + if (r == -1) + rb_raise (e_Error, "%s", guestfs_last_error (g)); + + return INT2NUM (r); +} + /* Initialize the module. */ void Init__guestfs () { @@ -5131,4 +5247,14 @@ void Init__guestfs () ruby_guestfs_mkswap_L, 2); rb_define_method (c_guestfs, "mkswap_U", ruby_guestfs_mkswap_U, 2); + rb_define_method (c_guestfs, "mknod", + ruby_guestfs_mknod, 4); + rb_define_method (c_guestfs, "mkfifo", + ruby_guestfs_mkfifo, 2); + rb_define_method (c_guestfs, "mknod_b", + ruby_guestfs_mknod_b, 4); + rb_define_method (c_guestfs, "mknod_c", + ruby_guestfs_mknod_c, 4); + rb_define_method (c_guestfs, "umask", + ruby_guestfs_umask, 1); } diff --git a/src/MAX_PROC_NR b/src/MAX_PROC_NR index 94361d4..065fd3e 100644 --- a/src/MAX_PROC_NR +++ b/src/MAX_PROC_NR @@ -1 +1 @@ -132 +137 diff --git a/src/guestfs-actions.c b/src/guestfs-actions.c index e81245a..a46b339 100644 --- a/src/guestfs-actions.c +++ b/src/guestfs-actions.c @@ -12100,3 +12100,463 @@ int guestfs_mkswap_U (guestfs_h *g, return 0; } +struct mknod_ctx { + /* This flag is set by the callbacks, so we know we've done + * the callbacks as expected, and in the right sequence. + * 0 = not called, 1 = reply_cb called. + */ + int cb_sequence; + struct guestfs_message_header hdr; + struct guestfs_message_error err; +}; + +static void mknod_reply_cb (guestfs_h *g, void *data, XDR *xdr) +{ + guestfs_main_loop *ml = guestfs_get_main_loop (g); + struct mknod_ctx *ctx = (struct mknod_ctx *) data; + + /* This should definitely not happen. */ + if (ctx->cb_sequence != 0) { + ctx->cb_sequence = 9999; + error (g, "%s: internal error: reply callback called twice", "guestfs_mknod"); + return; + } + + ml->main_loop_quit (ml, g); + + if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) { + error (g, "%s: failed to parse reply header", "guestfs_mknod"); + return; + } + if (ctx->hdr.status == GUESTFS_STATUS_ERROR) { + if (!xdr_guestfs_message_error (xdr, &ctx->err)) { + error (g, "%s: failed to parse reply error", "guestfs_mknod"); + return; + } + goto done; + } + done: + ctx->cb_sequence = 1; +} + +int guestfs_mknod (guestfs_h *g, + int mode, + int devmajor, + int devminor, + const char *path) +{ + struct guestfs_mknod_args args; + struct mknod_ctx ctx; + guestfs_main_loop *ml = guestfs_get_main_loop (g); + int serial; + + if (check_state (g, "guestfs_mknod") == -1) return -1; + guestfs_set_busy (g); + + memset (&ctx, 0, sizeof ctx); + + args.mode = mode; + args.devmajor = devmajor; + args.devminor = devminor; + args.path = (char *) path; + serial = guestfs__send_sync (g, GUESTFS_PROC_MKNOD, + (xdrproc_t) xdr_guestfs_mknod_args, (char *) &args); + if (serial == -1) { + guestfs_end_busy (g); + return -1; + } + + guestfs__switch_to_receiving (g); + ctx.cb_sequence = 0; + guestfs_set_reply_callback (g, mknod_reply_cb, &ctx); + (void) ml->main_loop_run (ml, g); + guestfs_set_reply_callback (g, NULL, NULL); + if (ctx.cb_sequence != 1) { + error (g, "%s reply failed, see earlier error messages", "guestfs_mknod"); + guestfs_end_busy (g); + return -1; + } + + if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_MKNOD, serial) == -1) { + guestfs_end_busy (g); + return -1; + } + + if (ctx.hdr.status == GUESTFS_STATUS_ERROR) { + error (g, "%s", ctx.err.error_message); + free (ctx.err.error_message); + guestfs_end_busy (g); + return -1; + } + + guestfs_end_busy (g); + return 0; +} + +struct mkfifo_ctx { + /* This flag is set by the callbacks, so we know we've done + * the callbacks as expected, and in the right sequence. + * 0 = not called, 1 = reply_cb called. + */ + int cb_sequence; + struct guestfs_message_header hdr; + struct guestfs_message_error err; +}; + +static void mkfifo_reply_cb (guestfs_h *g, void *data, XDR *xdr) +{ + guestfs_main_loop *ml = guestfs_get_main_loop (g); + struct mkfifo_ctx *ctx = (struct mkfifo_ctx *) data; + + /* This should definitely not happen. */ + if (ctx->cb_sequence != 0) { + ctx->cb_sequence = 9999; + error (g, "%s: internal error: reply callback called twice", "guestfs_mkfifo"); + return; + } + + ml->main_loop_quit (ml, g); + + if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) { + error (g, "%s: failed to parse reply header", "guestfs_mkfifo"); + return; + } + if (ctx->hdr.status == GUESTFS_STATUS_ERROR) { + if (!xdr_guestfs_message_error (xdr, &ctx->err)) { + error (g, "%s: failed to parse reply error", "guestfs_mkfifo"); + return; + } + goto done; + } + done: + ctx->cb_sequence = 1; +} + +int guestfs_mkfifo (guestfs_h *g, + int mode, + const char *path) +{ + struct guestfs_mkfifo_args args; + struct mkfifo_ctx ctx; + guestfs_main_loop *ml = guestfs_get_main_loop (g); + int serial; + + if (check_state (g, "guestfs_mkfifo") == -1) return -1; + guestfs_set_busy (g); + + memset (&ctx, 0, sizeof ctx); + + args.mode = mode; + args.path = (char *) path; + serial = guestfs__send_sync (g, GUESTFS_PROC_MKFIFO, + (xdrproc_t) xdr_guestfs_mkfifo_args, (char *) &args); + if (serial == -1) { + guestfs_end_busy (g); + return -1; + } + + guestfs__switch_to_receiving (g); + ctx.cb_sequence = 0; + guestfs_set_reply_callback (g, mkfifo_reply_cb, &ctx); + (void) ml->main_loop_run (ml, g); + guestfs_set_reply_callback (g, NULL, NULL); + if (ctx.cb_sequence != 1) { + error (g, "%s reply failed, see earlier error messages", "guestfs_mkfifo"); + guestfs_end_busy (g); + return -1; + } + + if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_MKFIFO, serial) == -1) { + guestfs_end_busy (g); + return -1; + } + + if (ctx.hdr.status == GUESTFS_STATUS_ERROR) { + error (g, "%s", ctx.err.error_message); + free (ctx.err.error_message); + guestfs_end_busy (g); + return -1; + } + + guestfs_end_busy (g); + return 0; +} + +struct mknod_b_ctx { + /* This flag is set by the callbacks, so we know we've done + * the callbacks as expected, and in the right sequence. + * 0 = not called, 1 = reply_cb called. + */ + int cb_sequence; + struct guestfs_message_header hdr; + struct guestfs_message_error err; +}; + +static void mknod_b_reply_cb (guestfs_h *g, void *data, XDR *xdr) +{ + guestfs_main_loop *ml = guestfs_get_main_loop (g); + struct mknod_b_ctx *ctx = (struct mknod_b_ctx *) data; + + /* This should definitely not happen. */ + if (ctx->cb_sequence != 0) { + ctx->cb_sequence = 9999; + error (g, "%s: internal error: reply callback called twice", "guestfs_mknod_b"); + return; + } + + ml->main_loop_quit (ml, g); + + if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) { + error (g, "%s: failed to parse reply header", "guestfs_mknod_b"); + return; + } + if (ctx->hdr.status == GUESTFS_STATUS_ERROR) { + if (!xdr_guestfs_message_error (xdr, &ctx->err)) { + error (g, "%s: failed to parse reply error", "guestfs_mknod_b"); + return; + } + goto done; + } + done: + ctx->cb_sequence = 1; +} + +int guestfs_mknod_b (guestfs_h *g, + int mode, + int devmajor, + int devminor, + const char *path) +{ + struct guestfs_mknod_b_args args; + struct mknod_b_ctx ctx; + guestfs_main_loop *ml = guestfs_get_main_loop (g); + int serial; + + if (check_state (g, "guestfs_mknod_b") == -1) return -1; + guestfs_set_busy (g); + + memset (&ctx, 0, sizeof ctx); + + args.mode = mode; + args.devmajor = devmajor; + args.devminor = devminor; + args.path = (char *) path; + serial = guestfs__send_sync (g, GUESTFS_PROC_MKNOD_B, + (xdrproc_t) xdr_guestfs_mknod_b_args, (char *) &args); + if (serial == -1) { + guestfs_end_busy (g); + return -1; + } + + guestfs__switch_to_receiving (g); + ctx.cb_sequence = 0; + guestfs_set_reply_callback (g, mknod_b_reply_cb, &ctx); + (void) ml->main_loop_run (ml, g); + guestfs_set_reply_callback (g, NULL, NULL); + if (ctx.cb_sequence != 1) { + error (g, "%s reply failed, see earlier error messages", "guestfs_mknod_b"); + guestfs_end_busy (g); + return -1; + } + + if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_MKNOD_B, serial) == -1) { + guestfs_end_busy (g); + return -1; + } + + if (ctx.hdr.status == GUESTFS_STATUS_ERROR) { + error (g, "%s", ctx.err.error_message); + free (ctx.err.error_message); + guestfs_end_busy (g); + return -1; + } + + guestfs_end_busy (g); + return 0; +} + +struct mknod_c_ctx { + /* This flag is set by the callbacks, so we know we've done + * the callbacks as expected, and in the right sequence. + * 0 = not called, 1 = reply_cb called. + */ + int cb_sequence; + struct guestfs_message_header hdr; + struct guestfs_message_error err; +}; + +static void mknod_c_reply_cb (guestfs_h *g, void *data, XDR *xdr) +{ + guestfs_main_loop *ml = guestfs_get_main_loop (g); + struct mknod_c_ctx *ctx = (struct mknod_c_ctx *) data; + + /* This should definitely not happen. */ + if (ctx->cb_sequence != 0) { + ctx->cb_sequence = 9999; + error (g, "%s: internal error: reply callback called twice", "guestfs_mknod_c"); + return; + } + + ml->main_loop_quit (ml, g); + + if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) { + error (g, "%s: failed to parse reply header", "guestfs_mknod_c"); + return; + } + if (ctx->hdr.status == GUESTFS_STATUS_ERROR) { + if (!xdr_guestfs_message_error (xdr, &ctx->err)) { + error (g, "%s: failed to parse reply error", "guestfs_mknod_c"); + return; + } + goto done; + } + done: + ctx->cb_sequence = 1; +} + +int guestfs_mknod_c (guestfs_h *g, + int mode, + int devmajor, + int devminor, + const char *path) +{ + struct guestfs_mknod_c_args args; + struct mknod_c_ctx ctx; + guestfs_main_loop *ml = guestfs_get_main_loop (g); + int serial; + + if (check_state (g, "guestfs_mknod_c") == -1) return -1; + guestfs_set_busy (g); + + memset (&ctx, 0, sizeof ctx); + + args.mode = mode; + args.devmajor = devmajor; + args.devminor = devminor; + args.path = (char *) path; + serial = guestfs__send_sync (g, GUESTFS_PROC_MKNOD_C, + (xdrproc_t) xdr_guestfs_mknod_c_args, (char *) &args); + if (serial == -1) { + guestfs_end_busy (g); + return -1; + } + + guestfs__switch_to_receiving (g); + ctx.cb_sequence = 0; + guestfs_set_reply_callback (g, mknod_c_reply_cb, &ctx); + (void) ml->main_loop_run (ml, g); + guestfs_set_reply_callback (g, NULL, NULL); + if (ctx.cb_sequence != 1) { + error (g, "%s reply failed, see earlier error messages", "guestfs_mknod_c"); + guestfs_end_busy (g); + return -1; + } + + if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_MKNOD_C, serial) == -1) { + guestfs_end_busy (g); + return -1; + } + + if (ctx.hdr.status == GUESTFS_STATUS_ERROR) { + error (g, "%s", ctx.err.error_message); + free (ctx.err.error_message); + guestfs_end_busy (g); + return -1; + } + + guestfs_end_busy (g); + return 0; +} + +struct umask_ctx { + /* This flag is set by the callbacks, so we know we've done + * the callbacks as expected, and in the right sequence. + * 0 = not called, 1 = reply_cb called. + */ + int cb_sequence; + struct guestfs_message_header hdr; + struct guestfs_message_error err; + struct guestfs_umask_ret ret; +}; + +static void umask_reply_cb (guestfs_h *g, void *data, XDR *xdr) +{ + guestfs_main_loop *ml = guestfs_get_main_loop (g); + struct umask_ctx *ctx = (struct umask_ctx *) data; + + /* This should definitely not happen. */ + if (ctx->cb_sequence != 0) { + ctx->cb_sequence = 9999; + error (g, "%s: internal error: reply callback called twice", "guestfs_umask"); + return; + } + + ml->main_loop_quit (ml, g); + + if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) { + error (g, "%s: failed to parse reply header", "guestfs_umask"); + return; + } + if (ctx->hdr.status == GUESTFS_STATUS_ERROR) { + if (!xdr_guestfs_message_error (xdr, &ctx->err)) { + error (g, "%s: failed to parse reply error", "guestfs_umask"); + return; + } + goto done; + } + if (!xdr_guestfs_umask_ret (xdr, &ctx->ret)) { + error (g, "%s: failed to parse reply", "guestfs_umask"); + return; + } + done: + ctx->cb_sequence = 1; +} + +int guestfs_umask (guestfs_h *g, + int mask) +{ + struct guestfs_umask_args args; + struct umask_ctx ctx; + guestfs_main_loop *ml = guestfs_get_main_loop (g); + int serial; + + if (check_state (g, "guestfs_umask") == -1) return -1; + guestfs_set_busy (g); + + memset (&ctx, 0, sizeof ctx); + + args.mask = mask; + serial = guestfs__send_sync (g, GUESTFS_PROC_UMASK, + (xdrproc_t) xdr_guestfs_umask_args, (char *) &args); + if (serial == -1) { + guestfs_end_busy (g); + return -1; + } + + guestfs__switch_to_receiving (g); + ctx.cb_sequence = 0; + guestfs_set_reply_callback (g, umask_reply_cb, &ctx); + (void) ml->main_loop_run (ml, g); + guestfs_set_reply_callback (g, NULL, NULL); + if (ctx.cb_sequence != 1) { + error (g, "%s reply failed, see earlier error messages", "guestfs_umask"); + guestfs_end_busy (g); + return -1; + } + + if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_UMASK, serial) == -1) { + guestfs_end_busy (g); + return -1; + } + + if (ctx.hdr.status == GUESTFS_STATUS_ERROR) { + error (g, "%s", ctx.err.error_message); + free (ctx.err.error_message); + guestfs_end_busy (g); + return -1; + } + + guestfs_end_busy (g); + return ctx.ret.oldmask; +} + diff --git a/src/guestfs-actions.h b/src/guestfs-actions.h index 80727ae..5300d15 100644 --- a/src/guestfs-actions.h +++ b/src/guestfs-actions.h @@ -205,3 +205,8 @@ extern int guestfs_mount_loop (guestfs_h *handle, const char *file, const char * extern int guestfs_mkswap (guestfs_h *handle, const char *device); extern int guestfs_mkswap_L (guestfs_h *handle, const char *label, const char *device); extern int guestfs_mkswap_U (guestfs_h *handle, const char *uuid, const char *device); +extern int guestfs_mknod (guestfs_h *handle, int mode, int devmajor, int devminor, const char *path); +extern int guestfs_mkfifo (guestfs_h *handle, int mode, const char *path); +extern int guestfs_mknod_b (guestfs_h *handle, int mode, int devmajor, int devminor, const char *path); +extern int guestfs_mknod_c (guestfs_h *handle, int mode, int devmajor, int devminor, const char *path); +extern int guestfs_umask (guestfs_h *handle, int mask); diff --git a/src/guestfs_protocol.c b/src/guestfs_protocol.c index 37c74da..ef0b805 100644 --- a/src/guestfs_protocol.c +++ b/src/guestfs_protocol.c @@ -2238,6 +2238,203 @@ xdr_guestfs_mkswap_U_args (XDR *xdrs, guestfs_mkswap_U_args *objp) } bool_t +xdr_guestfs_mknod_args (XDR *xdrs, guestfs_mknod_args *objp) +{ + register int32_t *buf; + + + if (xdrs->x_op == XDR_ENCODE) { + buf = XDR_INLINE (xdrs, 3 * BYTES_PER_XDR_UNIT); + if (buf == NULL) { + if (!xdr_int (xdrs, &objp->mode)) + return FALSE; + if (!xdr_int (xdrs, &objp->devmajor)) + return FALSE; + if (!xdr_int (xdrs, &objp->devminor)) + return FALSE; + + } else { + IXDR_PUT_LONG(buf, objp->mode); + IXDR_PUT_LONG(buf, objp->devmajor); + IXDR_PUT_LONG(buf, objp->devminor); + } + if (!xdr_string (xdrs, &objp->path, ~0)) + return FALSE; + return TRUE; + } else if (xdrs->x_op == XDR_DECODE) { + buf = XDR_INLINE (xdrs, 3 * BYTES_PER_XDR_UNIT); + if (buf == NULL) { + if (!xdr_int (xdrs, &objp->mode)) + return FALSE; + if (!xdr_int (xdrs, &objp->devmajor)) + return FALSE; + if (!xdr_int (xdrs, &objp->devminor)) + return FALSE; + + } else { + objp->mode = IXDR_GET_LONG(buf); + objp->devmajor = IXDR_GET_LONG(buf); + objp->devminor = IXDR_GET_LONG(buf); + } + if (!xdr_string (xdrs, &objp->path, ~0)) + return FALSE; + return TRUE; + } + + if (!xdr_int (xdrs, &objp->mode)) + return FALSE; + if (!xdr_int (xdrs, &objp->devmajor)) + return FALSE; + if (!xdr_int (xdrs, &objp->devminor)) + return FALSE; + if (!xdr_string (xdrs, &objp->path, ~0)) + return FALSE; + return TRUE; +} + +bool_t +xdr_guestfs_mkfifo_args (XDR *xdrs, guestfs_mkfifo_args *objp) +{ + register int32_t *buf; + + if (!xdr_int (xdrs, &objp->mode)) + return FALSE; + if (!xdr_string (xdrs, &objp->path, ~0)) + return FALSE; + return TRUE; +} + +bool_t +xdr_guestfs_mknod_b_args (XDR *xdrs, guestfs_mknod_b_args *objp) +{ + register int32_t *buf; + + + if (xdrs->x_op == XDR_ENCODE) { + buf = XDR_INLINE (xdrs, 3 * BYTES_PER_XDR_UNIT); + if (buf == NULL) { + if (!xdr_int (xdrs, &objp->mode)) + return FALSE; + if (!xdr_int (xdrs, &objp->devmajor)) + return FALSE; + if (!xdr_int (xdrs, &objp->devminor)) + return FALSE; + + } else { + IXDR_PUT_LONG(buf, objp->mode); + IXDR_PUT_LONG(buf, objp->devmajor); + IXDR_PUT_LONG(buf, objp->devminor); + } + if (!xdr_string (xdrs, &objp->path, ~0)) + return FALSE; + return TRUE; + } else if (xdrs->x_op == XDR_DECODE) { + buf = XDR_INLINE (xdrs, 3 * BYTES_PER_XDR_UNIT); + if (buf == NULL) { + if (!xdr_int (xdrs, &objp->mode)) + return FALSE; + if (!xdr_int (xdrs, &objp->devmajor)) + return FALSE; + if (!xdr_int (xdrs, &objp->devminor)) + return FALSE; + + } else { + objp->mode = IXDR_GET_LONG(buf); + objp->devmajor = IXDR_GET_LONG(buf); + objp->devminor = IXDR_GET_LONG(buf); + } + if (!xdr_string (xdrs, &objp->path, ~0)) + return FALSE; + return TRUE; + } + + if (!xdr_int (xdrs, &objp->mode)) + return FALSE; + if (!xdr_int (xdrs, &objp->devmajor)) + return FALSE; + if (!xdr_int (xdrs, &objp->devminor)) + return FALSE; + if (!xdr_string (xdrs, &objp->path, ~0)) + return FALSE; + return TRUE; +} + +bool_t +xdr_guestfs_mknod_c_args (XDR *xdrs, guestfs_mknod_c_args *objp) +{ + register int32_t *buf; + + + if (xdrs->x_op == XDR_ENCODE) { + buf = XDR_INLINE (xdrs, 3 * BYTES_PER_XDR_UNIT); + if (buf == NULL) { + if (!xdr_int (xdrs, &objp->mode)) + return FALSE; + if (!xdr_int (xdrs, &objp->devmajor)) + return FALSE; + if (!xdr_int (xdrs, &objp->devminor)) + return FALSE; + + } else { + IXDR_PUT_LONG(buf, objp->mode); + IXDR_PUT_LONG(buf, objp->devmajor); + IXDR_PUT_LONG(buf, objp->devminor); + } + if (!xdr_string (xdrs, &objp->path, ~0)) + return FALSE; + return TRUE; + } else if (xdrs->x_op == XDR_DECODE) { + buf = XDR_INLINE (xdrs, 3 * BYTES_PER_XDR_UNIT); + if (buf == NULL) { + if (!xdr_int (xdrs, &objp->mode)) + return FALSE; + if (!xdr_int (xdrs, &objp->devmajor)) + return FALSE; + if (!xdr_int (xdrs, &objp->devminor)) + return FALSE; + + } else { + objp->mode = IXDR_GET_LONG(buf); + objp->devmajor = IXDR_GET_LONG(buf); + objp->devminor = IXDR_GET_LONG(buf); + } + if (!xdr_string (xdrs, &objp->path, ~0)) + return FALSE; + return TRUE; + } + + if (!xdr_int (xdrs, &objp->mode)) + return FALSE; + if (!xdr_int (xdrs, &objp->devmajor)) + return FALSE; + if (!xdr_int (xdrs, &objp->devminor)) + return FALSE; + if (!xdr_string (xdrs, &objp->path, ~0)) + return FALSE; + return TRUE; +} + +bool_t +xdr_guestfs_umask_args (XDR *xdrs, guestfs_umask_args *objp) +{ + register int32_t *buf; + + if (!xdr_int (xdrs, &objp->mask)) + return FALSE; + return TRUE; +} + +bool_t +xdr_guestfs_umask_ret (XDR *xdrs, guestfs_umask_ret *objp) +{ + register int32_t *buf; + + if (!xdr_int (xdrs, &objp->oldmask)) + return FALSE; + return TRUE; +} + +bool_t xdr_guestfs_procedure (XDR *xdrs, guestfs_procedure *objp) { register int32_t *buf; diff --git a/src/guestfs_protocol.h b/src/guestfs_protocol.h index 7931bb5..3b508b2 100644 --- a/src/guestfs_protocol.h +++ b/src/guestfs_protocol.h @@ -1147,6 +1147,46 @@ struct guestfs_mkswap_U_args { }; typedef struct guestfs_mkswap_U_args guestfs_mkswap_U_args; +struct guestfs_mknod_args { + int mode; + int devmajor; + int devminor; + char *path; +}; +typedef struct guestfs_mknod_args guestfs_mknod_args; + +struct guestfs_mkfifo_args { + int mode; + char *path; +}; +typedef struct guestfs_mkfifo_args guestfs_mkfifo_args; + +struct guestfs_mknod_b_args { + int mode; + int devmajor; + int devminor; + char *path; +}; +typedef struct guestfs_mknod_b_args guestfs_mknod_b_args; + +struct guestfs_mknod_c_args { + int mode; + int devmajor; + int devminor; + char *path; +}; +typedef struct guestfs_mknod_c_args guestfs_mknod_c_args; + +struct guestfs_umask_args { + int mask; +}; +typedef struct guestfs_umask_args guestfs_umask_args; + +struct guestfs_umask_ret { + int oldmask; +}; +typedef struct guestfs_umask_ret guestfs_umask_ret; + enum guestfs_procedure { GUESTFS_PROC_MOUNT = 1, GUESTFS_PROC_SYNC = 2, @@ -1280,7 +1320,12 @@ enum guestfs_procedure { GUESTFS_PROC_MKSWAP = 130, GUESTFS_PROC_MKSWAP_L = 131, GUESTFS_PROC_MKSWAP_U = 132, - GUESTFS_PROC_NR_PROCS = 132 + 1, + GUESTFS_PROC_MKNOD = 133, + GUESTFS_PROC_MKFIFO = 134, + GUESTFS_PROC_MKNOD_B = 135, + GUESTFS_PROC_MKNOD_C = 136, + GUESTFS_PROC_UMASK = 137, + GUESTFS_PROC_NR_PROCS = 137 + 1, }; typedef enum guestfs_procedure guestfs_procedure; #define GUESTFS_MESSAGE_MAX 4194304 @@ -1516,6 +1561,12 @@ extern bool_t xdr_guestfs_mount_loop_args (XDR *, guestfs_mount_loop_args*); extern bool_t xdr_guestfs_mkswap_args (XDR *, guestfs_mkswap_args*); extern bool_t xdr_guestfs_mkswap_L_args (XDR *, guestfs_mkswap_L_args*); extern bool_t xdr_guestfs_mkswap_U_args (XDR *, guestfs_mkswap_U_args*); +extern bool_t xdr_guestfs_mknod_args (XDR *, guestfs_mknod_args*); +extern bool_t xdr_guestfs_mkfifo_args (XDR *, guestfs_mkfifo_args*); +extern bool_t xdr_guestfs_mknod_b_args (XDR *, guestfs_mknod_b_args*); +extern bool_t xdr_guestfs_mknod_c_args (XDR *, guestfs_mknod_c_args*); +extern bool_t xdr_guestfs_umask_args (XDR *, guestfs_umask_args*); +extern bool_t xdr_guestfs_umask_ret (XDR *, guestfs_umask_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*); @@ -1710,6 +1761,12 @@ extern bool_t xdr_guestfs_mount_loop_args (); extern bool_t xdr_guestfs_mkswap_args (); extern bool_t xdr_guestfs_mkswap_L_args (); extern bool_t xdr_guestfs_mkswap_U_args (); +extern bool_t xdr_guestfs_mknod_args (); +extern bool_t xdr_guestfs_mkfifo_args (); +extern bool_t xdr_guestfs_mknod_b_args (); +extern bool_t xdr_guestfs_mknod_c_args (); +extern bool_t xdr_guestfs_umask_args (); +extern bool_t xdr_guestfs_umask_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 5578284..bcc0138 100644 --- a/src/guestfs_protocol.x +++ b/src/guestfs_protocol.x @@ -877,6 +877,40 @@ struct guestfs_mkswap_U_args { string device<>; }; +struct guestfs_mknod_args { + int mode; + int devmajor; + int devminor; + string path<>; +}; + +struct guestfs_mkfifo_args { + int mode; + string path<>; +}; + +struct guestfs_mknod_b_args { + int mode; + int devmajor; + int devminor; + string path<>; +}; + +struct guestfs_mknod_c_args { + int mode; + int devmajor; + int devminor; + string path<>; +}; + +struct guestfs_umask_args { + int mask; +}; + +struct guestfs_umask_ret { + int oldmask; +}; + enum guestfs_procedure { GUESTFS_PROC_MOUNT = 1, GUESTFS_PROC_SYNC = 2, @@ -1010,6 +1044,11 @@ enum guestfs_procedure { GUESTFS_PROC_MKSWAP = 130, GUESTFS_PROC_MKSWAP_L = 131, GUESTFS_PROC_MKSWAP_U = 132, + GUESTFS_PROC_MKNOD = 133, + GUESTFS_PROC_MKFIFO = 134, + GUESTFS_PROC_MKNOD_B = 135, + GUESTFS_PROC_MKNOD_C = 136, + GUESTFS_PROC_UMASK = 137, GUESTFS_PROC_NR_PROCS }; -- 1.8.3.1