From ef107448e89c10899cefc27f887bd627c1d7e777 Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Fri, 14 Jun 2013 10:53:17 +0100 Subject: [PATCH] Add followsymlinks flag to is-file, is-dir, is-blockdev, is-chardev, is-fifo and is-socket APIs. This adds an extra optional boolean 'followsymlinks' flag to those 6 is-* APIs. If the flag is true, then symlinks are followed, ie. we use stat instead of lstat in the test. For the rationale behind this change, see: https://bugzilla.redhat.com/show_bug.cgi?id=974489 --- daemon/is.c | 72 ++++++++++++++++----- generator/actions.ml | 82 ++++++++++++++++-------- gobject/Makefile.inc | 12 ++++ po/POTFILES | 6 ++ sysprep/firstboot.ml | 4 +- sysprep/sysprep_operation_cron_spool.ml | 2 +- sysprep/sysprep_operation_hostname.ml | 2 +- sysprep/sysprep_operation_random_seed.ml | 2 +- 8 files changed, 135 insertions(+), 47 deletions(-) diff --git a/daemon/is.c b/daemon/is.c index f892ccfa3..4acdef685 100644 --- a/daemon/is.c +++ b/daemon/is.c @@ -1,5 +1,5 @@ /* libguestfs - the guestfsd daemon - * Copyright (C) 2010 Red Hat Inc. + * Copyright (C) 2010-2013 Red Hat Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -41,49 +41,79 @@ do_exists (const char *path) return r == 0; } -static int get_mode (const char *path, mode_t *mode); +static int get_mode (const char *path, mode_t *mode, int followsymlinks); +/* Takes optional arguments, consult optargs_bitmask. */ int -do_is_file (const char *path) +do_is_file (const char *path, int followsymlinks) { mode_t mode; - int r = get_mode (path, &mode); + int r; + + if (!(optargs_bitmask & GUESTFS_IS_FILE_FOLLOWSYMLINKS_BITMASK)) + followsymlinks = 0; + + r = get_mode (path, &mode, followsymlinks); if (r <= 0) return r; return S_ISREG (mode); } +/* Takes optional arguments, consult optargs_bitmask. */ int -do_is_dir (const char *path) +do_is_dir (const char *path, int followsymlinks) { mode_t mode; - int r = get_mode (path, &mode); + int r; + + if (!(optargs_bitmask & GUESTFS_IS_DIR_FOLLOWSYMLINKS_BITMASK)) + followsymlinks = 0; + + r = get_mode (path, &mode, followsymlinks); if (r <= 0) return r; return S_ISDIR (mode); } +/* Takes optional arguments, consult optargs_bitmask. */ int -do_is_chardev (const char *path) +do_is_chardev (const char *path, int followsymlinks) { mode_t mode; - int r = get_mode (path, &mode); + int r; + + if (!(optargs_bitmask & GUESTFS_IS_CHARDEV_FOLLOWSYMLINKS_BITMASK)) + followsymlinks = 0; + + r = get_mode (path, &mode, followsymlinks); if (r <= 0) return r; return S_ISCHR (mode); } +/* Takes optional arguments, consult optargs_bitmask. */ int -do_is_blockdev (const char *path) +do_is_blockdev (const char *path, int followsymlinks) { mode_t mode; - int r = get_mode (path, &mode); + int r; + + if (!(optargs_bitmask & GUESTFS_IS_BLOCKDEV_FOLLOWSYMLINKS_BITMASK)) + followsymlinks = 0; + + r = get_mode (path, &mode, followsymlinks); if (r <= 0) return r; return S_ISBLK (mode); } +/* Takes optional arguments, consult optargs_bitmask. */ int -do_is_fifo (const char *path) +do_is_fifo (const char *path, int followsymlinks) { mode_t mode; - int r = get_mode (path, &mode); + int r; + + if (!(optargs_bitmask & GUESTFS_IS_FIFO_FOLLOWSYMLINKS_BITMASK)) + followsymlinks = 0; + + r = get_mode (path, &mode, followsymlinks); if (r <= 0) return r; return S_ISFIFO (mode); } @@ -92,28 +122,36 @@ int do_is_symlink (const char *path) { mode_t mode; - int r = get_mode (path, &mode); + int r; + + r = get_mode (path, &mode, 0); if (r <= 0) return r; return S_ISLNK (mode); } +/* Takes optional arguments, consult optargs_bitmask. */ int -do_is_socket (const char *path) +do_is_socket (const char *path, int followsymlinks) { mode_t mode; - int r = get_mode (path, &mode); + int r; + + if (!(optargs_bitmask & GUESTFS_IS_SOCKET_FOLLOWSYMLINKS_BITMASK)) + followsymlinks = 0; + + r = get_mode (path, &mode, followsymlinks); if (r <= 0) return r; return S_ISSOCK (mode); } static int -get_mode (const char *path, mode_t *mode) +get_mode (const char *path, mode_t *mode, int followsymlinks) { int r; struct stat buf; CHROOT_IN; - r = lstat (path, &buf); + r = (!followsymlinks ? lstat : stat) (path, &buf); CHROOT_OUT; if (r == -1) { diff --git a/generator/actions.ml b/generator/actions.ml index 192072bd5..83a10805e 100644 --- a/generator/actions.ml +++ b/generator/actions.ml @@ -3471,7 +3471,7 @@ command." }; tests = [ InitScratchFS, Always, TestResultTrue [["mkdir"; "/mkdir"]; - ["is_dir"; "/mkdir"]]; + ["is_dir"; "/mkdir"; ""]]; InitScratchFS, Always, TestLastFail [["mkdir"; "/mkdir2/foo/bar"]] ]; @@ -3486,13 +3486,13 @@ Create a directory named C." }; tests = [ InitScratchFS, Always, TestResultTrue [["mkdir_p"; "/mkdir_p/foo/bar"]; - ["is_dir"; "/mkdir_p/foo/bar"]]; + ["is_dir"; "/mkdir_p/foo/bar"; ""]]; InitScratchFS, Always, TestResultTrue [["mkdir_p"; "/mkdir_p2/foo/bar"]; - ["is_dir"; "/mkdir_p2/foo"]]; + ["is_dir"; "/mkdir_p2/foo"; ""]]; InitScratchFS, Always, TestResultTrue [["mkdir_p"; "/mkdir_p3/foo/bar"]; - ["is_dir"; "/mkdir_p3"]]; + ["is_dir"; "/mkdir_p3"; ""]]; (* Regression tests for RHBZ#503133: *) InitScratchFS, Always, TestRun [["mkdir"; "/mkdir_p4"]; @@ -3554,13 +3554,16 @@ See also C, C, C." }; { defaults with name = "is_file"; - style = RBool "fileflag", [Pathname "path"], []; + style = RBool "fileflag", [Pathname "path"], [OBool "followsymlinks"]; proc_nr = Some 37; + once_had_no_optargs = true; tests = [ InitISOFS, Always, TestResultTrue ( - [["is_file"; "/known-1"]]); + [["is_file"; "/known-1"; ""]]); InitISOFS, Always, TestResultFalse ( - [["is_file"; "/directory"]]) + [["is_file"; "/directory"; ""]]); + InitISOFS, Always, TestResultTrue ( + [["is_file"; "/abssymlink"; "true"]]) ]; shortdesc = "test if a regular file"; longdesc = "\ @@ -3568,17 +3571,22 @@ This returns C if and only if there is a regular file with the given C name. Note that it returns false for other objects like directories. +If the optional flag C is true, then a symlink +(or chain of symlinks) that ends with a file also causes the +function to return true. + See also C." }; { defaults with name = "is_dir"; - style = RBool "dirflag", [Pathname "path"], []; + style = RBool "dirflag", [Pathname "path"], [OBool "followsymlinks"]; proc_nr = Some 38; + once_had_no_optargs = true; tests = [ InitISOFS, Always, TestResultFalse ( - [["is_dir"; "/known-3"]]); + [["is_dir"; "/known-3"; ""]]); InitISOFS, Always, TestResultTrue ( - [["is_dir"; "/directory"]]) + [["is_dir"; "/directory"; ""]]) ]; shortdesc = "test if a directory"; longdesc = "\ @@ -3586,6 +3594,10 @@ This returns C if and only if there is a directory with the given C name. Note that it returns false for other objects like files. +If the optional flag C is true, then a symlink +(or chain of symlinks) that ends with a directory also causes the +function to return true. + See also C." }; { defaults with @@ -4796,7 +4808,7 @@ C" }; [["mkdir_p"; "/boot/grub"]; ["write"; "/boot/grub/device.map"; "(hd0) /dev/sda"]; ["grub_install"; "/"; "/dev/sda"]; - ["is_dir"; "/boot"]]) + ["is_dir"; "/boot"; ""]]) ]; shortdesc = "install GRUB 1"; longdesc = "\ @@ -4850,7 +4862,7 @@ replacing C with the name of the installation device. [["mkdir"; "/cp2"]; ["write"; "/cp2/old"; "file content"]; ["cp"; "/cp2/old"; "/cp2/new"]; - ["is_file"; "/cp2/old"]]); + ["is_file"; "/cp2/old"; ""]]); InitScratchFS, Always, TestResultString ( [["mkdir"; "/cp3"]; ["write"; "/cp3/old"; "file content"]; @@ -4894,7 +4906,7 @@ recursively using the C command." }; [["mkdir"; "/mv2"]; ["write"; "/mv2/old"; "file content"]; ["mv"; "/mv2/old"; "/mv2/new"]; - ["is_file"; "/mv2/old"]]) + ["is_file"; "/mv2/old"; ""]]) ]; shortdesc = "move a file"; longdesc = "\ @@ -8373,56 +8385,71 @@ To find the label of a filesystem, use C." }; { defaults with name = "is_chardev"; - style = RBool "flag", [Pathname "path"], []; + style = RBool "flag", [Pathname "path"], [OBool "followsymlinks"]; proc_nr = Some 267; + once_had_no_optargs = true; tests = [ InitISOFS, Always, TestResultFalse ( - [["is_chardev"; "/directory"]]); + [["is_chardev"; "/directory"; ""]]); InitScratchFS, Always, TestResultTrue ( [["mknod_c"; "0o777"; "99"; "66"; "/is_chardev"]; - ["is_chardev"; "/is_chardev"]]) + ["is_chardev"; "/is_chardev"; ""]]) ]; shortdesc = "test if character device"; longdesc = "\ This returns C if and only if there is a character device with the given C name. +If the optional flag C is true, then a symlink +(or chain of symlinks) that ends with a chardev also causes the +function to return true. + See also C." }; { defaults with name = "is_blockdev"; - style = RBool "flag", [Pathname "path"], []; + style = RBool "flag", [Pathname "path"], [OBool "followsymlinks"]; proc_nr = Some 268; + once_had_no_optargs = true; tests = [ InitISOFS, Always, TestResultFalse ( - [["is_blockdev"; "/directory"]]); + [["is_blockdev"; "/directory"; ""]]); InitScratchFS, Always, TestResultTrue ( [["mknod_b"; "0o777"; "99"; "66"; "/is_blockdev"]; - ["is_blockdev"; "/is_blockdev"]]) + ["is_blockdev"; "/is_blockdev"; ""]]) ]; shortdesc = "test if block device"; longdesc = "\ This returns C if and only if there is a block device with the given C name. +If the optional flag C is true, then a symlink +(or chain of symlinks) that ends with a block device also causes the +function to return true. + See also C." }; { defaults with name = "is_fifo"; - style = RBool "flag", [Pathname "path"], []; + style = RBool "flag", [Pathname "path"], [OBool "followsymlinks"]; proc_nr = Some 269; + once_had_no_optargs = true; tests = [ InitISOFS, Always, TestResultFalse ( - [["is_fifo"; "/directory"]]); + [["is_fifo"; "/directory"; ""]]); InitScratchFS, Always, TestResultTrue ( [["mkfifo"; "0o777"; "/is_fifo"]; - ["is_fifo"; "/is_fifo"]]) + ["is_fifo"; "/is_fifo"; ""]]) ]; shortdesc = "test if FIFO (named pipe)"; longdesc = "\ This returns C if and only if there is a FIFO (named pipe) with the given C name. +If the optional flag C is true, then a symlink +(or chain of symlinks) that ends with a FIFO also causes the +function to return true. + See also C." }; { defaults with @@ -8444,18 +8471,23 @@ See also C." }; { defaults with name = "is_socket"; - style = RBool "flag", [Pathname "path"], []; + style = RBool "flag", [Pathname "path"], [OBool "followsymlinks"]; proc_nr = Some 271; + once_had_no_optargs = true; (* XXX Need a positive test for sockets. *) tests = [ InitISOFS, Always, TestResultFalse ( - [["is_socket"; "/directory"]]) + [["is_socket"; "/directory"; ""]]) ]; shortdesc = "test if socket"; longdesc = "\ This returns C if and only if there is a Unix domain socket with the given C name. +If the optional flag C is true, then a symlink +(or chain of symlinks) that ends with a socket also causes the +function to return true. + See also C." }; { defaults with @@ -11039,7 +11071,7 @@ for other partition types." }; [["mkdir"; "/rename"]; ["write"; "/rename/old"; "file content"]; ["rename"; "/rename/old"; "/rename/new"]; - ["is_file"; "/rename/old"]]) + ["is_file"; "/rename/old"; ""]]) ]; shortdesc = "rename a file on the same filesystem"; longdesc = "\ diff --git a/gobject/Makefile.inc b/gobject/Makefile.inc index f7d45fcaf..28727b643 100644 --- a/gobject/Makefile.inc +++ b/gobject/Makefile.inc @@ -51,11 +51,17 @@ guestfs_gobject_headers= \ include/guestfs-gobject/optargs-inspect_get_icon.h \ include/guestfs-gobject/optargs-mount_local.h \ include/guestfs-gobject/optargs-umount_local.h \ + include/guestfs-gobject/optargs-is_file.h \ + include/guestfs-gobject/optargs-is_dir.h \ include/guestfs-gobject/optargs-umount.h \ include/guestfs-gobject/optargs-tar_in.h \ include/guestfs-gobject/optargs-tar_out.h \ include/guestfs-gobject/optargs-mkswap.h \ include/guestfs-gobject/optargs-grep.h \ + include/guestfs-gobject/optargs-is_chardev.h \ + include/guestfs-gobject/optargs-is_blockdev.h \ + include/guestfs-gobject/optargs-is_fifo.h \ + include/guestfs-gobject/optargs-is_socket.h \ include/guestfs-gobject/optargs-mkfs.h \ include/guestfs-gobject/optargs-mount_9p.h \ include/guestfs-gobject/optargs-ntfsresize.h \ @@ -118,11 +124,17 @@ guestfs_gobject_sources= \ src/optargs-inspect_get_icon.c \ src/optargs-mount_local.c \ src/optargs-umount_local.c \ + src/optargs-is_file.c \ + src/optargs-is_dir.c \ src/optargs-umount.c \ src/optargs-tar_in.c \ src/optargs-tar_out.c \ src/optargs-mkswap.c \ src/optargs-grep.c \ + src/optargs-is_chardev.c \ + src/optargs-is_blockdev.c \ + src/optargs-is_fifo.c \ + src/optargs-is_socket.c \ src/optargs-mkfs.c \ src/optargs-mount_9p.c \ src/optargs-ntfsresize.c \ diff --git a/po/POTFILES b/po/POTFILES index 327fc2046..bc8fbddeb 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -165,6 +165,12 @@ gobject/src/optargs-inspect_get_icon.c gobject/src/optargs-internal_test.c gobject/src/optargs-internal_test_63_optargs.c gobject/src/optargs-internal_test_only_optargs.c +gobject/src/optargs-is_blockdev.c +gobject/src/optargs-is_chardev.c +gobject/src/optargs-is_dir.c +gobject/src/optargs-is_fifo.c +gobject/src/optargs-is_file.c +gobject/src/optargs-is_socket.c gobject/src/optargs-md_create.c gobject/src/optargs-mke2fs.c gobject/src/optargs-mkfs.c diff --git a/sysprep/firstboot.ml b/sysprep/firstboot.ml index 7d493797c..16e921223 100644 --- a/sysprep/firstboot.ml +++ b/sysprep/firstboot.ml @@ -77,7 +77,7 @@ WantedBy=default.target let failed fs = ksprintf (fun msg -> failwith (s_"firstboot: failed: " ^ msg)) fs -let rec install_service g distro = +let rec install_service (g : Guestfs.guestfs) distro = g#mkdir_p firstboot_dir; g#mkdir_p (sprintf "%s/scripts" firstboot_dir); g#write (sprintf "%s/firstboot.sh" firstboot_dir) firstboot_sh; @@ -145,7 +145,7 @@ and install_sysvinit_debian g = g#ln_sf "/etc/init.d/virt-sysprep-firstboot" "/etc/rc5.d/S99virt-sysprep-firstboot" -let add_firstboot_script g root id content = +let add_firstboot_script (g : Guestfs.guestfs) root id content = let typ = g#inspect_get_type root in let distro = g#inspect_get_distro root in match typ, distro with diff --git a/sysprep/sysprep_operation_cron_spool.ml b/sysprep/sysprep_operation_cron_spool.ml index 90eea0336..f61769d68 100644 --- a/sysprep/sysprep_operation_cron_spool.ml +++ b/sysprep/sysprep_operation_cron_spool.ml @@ -21,7 +21,7 @@ open Common_gettext.Gettext module G = Guestfs -let cron_spool_perform g root = +let cron_spool_perform (g : Guestfs.guestfs) root = Array.iter g#rm_rf (g#glob_expand "/var/spool/cron/*"); Array.iter g#rm (g#glob_expand "/var/spool/atjobs/*"); Array.iter g#rm (g#glob_expand "/var/spool/atjobs/.SEQ"); diff --git a/sysprep/sysprep_operation_hostname.ml b/sysprep/sysprep_operation_hostname.ml index d38335ec8..e8767f369 100644 --- a/sysprep/sysprep_operation_hostname.ml +++ b/sysprep/sysprep_operation_hostname.ml @@ -26,7 +26,7 @@ module G = Guestfs let hostname = ref "localhost.localdomain" -let hostname_perform g root = +let hostname_perform (g : Guestfs.guestfs) root = let typ = g#inspect_get_type root in let distro = g#inspect_get_distro root in let major_version = g#inspect_get_major_version root in diff --git a/sysprep/sysprep_operation_random_seed.ml b/sysprep/sysprep_operation_random_seed.ml index 6beb16f52..c3d0dc58c 100644 --- a/sysprep/sysprep_operation_random_seed.ml +++ b/sysprep/sysprep_operation_random_seed.ml @@ -21,7 +21,7 @@ open Common_gettext.Gettext module G = Guestfs -let random_seed_perform g root = +let random_seed_perform (g : Guestfs.guestfs) root = let typ = g#inspect_get_type root in if typ = "linux" then ( let files = [