[CRIU] [RFC PATCH 01/21] zdtm: zdtm.py: elaborate file copying logic for ns tests

Andrew Vagin avagin at virtuozzo.com
Thu Feb 25 12:01:13 PST 2016


On Fri, Feb 19, 2016 at 05:50:24PM +0300, Ivan Shapovalov wrote:
> From: Ivan Shapovalov <intelfx100 at gmail.com>
> 
> When copying files (tests' deps and supplementary binaries) to the "chroot",
> do not blindly copy them using provided pathes (like "/sbin/iptables").
> Instead, walk the path manually and replicate all encountered symlinks in
> the "chroot".
> 
> This helps to support setups like Arch, where /{,s}bin are links to /usr/bin,
> and only /usr/bin is in $PATH.

Why is it not enough to call os.path.realpath?
> 
> Signed-off-by: Ivan Shapovalov <intelfx at intelfx.name>
> ---
>  test/zdtm.py | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++----------
>  1 file changed, 61 insertions(+), 11 deletions(-)
> 
> diff --git a/test/zdtm.py b/test/zdtm.py
> index 01b20e7..79b7a95 100755
> --- a/test/zdtm.py
> +++ b/test/zdtm.py
> @@ -105,8 +105,15 @@ class host_flavor:
>  	def clean():
>  		pass
>  
> +def splitall(path, tail = []):
> +	(dir, name) = os.path.split(path)
> +	if dir and dir != path:
> +		return splitall(dir, [name] + tail)
> +	else:
> +		return [dir or name] + tail
> +
>  class ns_flavor:
> -	__root_dirs = ["/bin", "/sbin", "/etc", "/lib", "/lib64", "/dev", "/dev/pts", "/dev/net", "/tmp", "/usr", "/proc"]
> +	__root_dirs = ["/etc", "/dev", "/dev/pts", "/dev/net", "/tmp", "/proc"]
>  
>  	def __init__(self, opts):
>  		self.name = "ns"
> @@ -115,18 +122,64 @@ class ns_flavor:
>  		self.root = make_tests_root()
>  		self.root_mounted = False
>  
> -	def __copy_one(self, fname):
> -		tfname = self.root + fname
> -		if not os.access(tfname, os.F_OK):
> +	def __copy_one(self, src):
> +		#
> +		# let's copy the whole subhierarchy, accounting neatly for cases like /sbin/iptables on Arch
> +		# (where /sbin -> /usr/bin, /usr/bin/iptables -> /usr/bin/xtables-multi, and only /usr/bin is in $PATH).`
> +		#
> +
> +		src_bits = splitall(src)
> +		if src_bits[0] != "/":
> +			raise test_fail_exc("Deps check (%s is not absolute)" % src)
> +		del src_bits[0]
> +
> +		src_dir_so_far = "/"
> +
> +		# copy all directories and links accurately
> +		for bit_src in src_bits:
> +			src_so_far = os.path.join(src_dir_so_far, bit_src)
> +			dest_so_far = self.root + src_so_far
> +
> +			# handle chained symlinks
> +			while os.path.islink(src_so_far):
> +				bit_dst = os.readlink(src_so_far)
> +				# relativize symlink target
> +				bit_dst_rel = os.path.relpath(bit_dst, src_dir_so_far) if os.path.isabs(bit_dst) else bit_dst

Can you avoid long lines? Our coding style says that a length should be
shorter than 80 symbols and it must be shorter than 120.
> +
> +				try:
> +					os.symlink(bit_dst_rel, dest_so_far)
> +				except:
> +					pass

I don't like an idea to ignore all exceptions. Can we ignore EEXIST
only?
> +
> +				src_so_far = os.path.join(src_dir_so_far, bit_dst)
> +				dest_so_far = self.root + src_so_far
> +				src_dir_so_far = os.path.dirname(src_so_far)
> +				try:
> +					os.makedirs(os.path.dirname(dest_so_far))
> +				except:
> +					pass
> +
> +			if os.path.isdir(src_so_far):
> +				src_dir_so_far = src_so_far
> +				try:
> +					os.makedirs(dest_so_far)
> +				except:
> +					pass
> +			else:
> +				break
> +
> +		# finally, copy the file itself
> +		real_dest = self.root + os.path.realpath(src)
> +		if not os.access(real_dest, os.F_OK):
>  			# Copying should be atomic as tests can be
>  			# run in parallel
>  			try:
> -				os.makedirs(self.root + os.path.dirname(fname))
> +				os.makedirs(os.path.dirname(real_dest))
>  			except:
>  				pass
> -			dst = tempfile.mktemp(".tso", "", self.root + os.path.dirname(fname))
> -			shutil.copy2(fname, dst)
> -			os.rename(dst, tfname)
> +			temp = tempfile.mktemp(".tso", "", os.path.dirname(real_dest))
> +			shutil.copy2(src, temp)
> +			os.rename(temp, real_dest)
>  
>  	def __copy_libs(self, binary):
>  		ldd = subprocess.Popen(["ldd", binary], stdout = subprocess.PIPE)
> @@ -164,9 +217,6 @@ class ns_flavor:
>  			os.mkdir(self.root + dir)
>  			os.chmod(self.root + dir, 0777)
>  
> -		for ldir in [ "/bin", "/sbin", "/lib", "/lib64" ]:
> -			os.symlink(".." + ldir, self.root + "/usr" + ldir)
> -
>  		self.__mknod("tty", os.makedev(5, 0))
>  		self.__mknod("null", os.makedev(1, 3))
>  		self.__mknod("net/tun")
> -- 
> 2.7.1
> 
> _______________________________________________
> CRIU mailing list
> CRIU at openvz.org
> https://lists.openvz.org/mailman/listinfo/criu


More information about the CRIU mailing list