tools/userland-fetch
changeset 5244 c63fce595432
parent 4429 a6c5fd1cbbc9
child 5682 94c0ca64c022
equal deleted inserted replaced
5243:cb29cf94919d 5244:c63fce595432
    17 # fields enclosed by brackets "[]" replaced with your own identifying
    17 # fields enclosed by brackets "[]" replaced with your own identifying
    18 # information: Portions Copyright [yyyy] [name of copyright owner]
    18 # information: Portions Copyright [yyyy] [name of copyright owner]
    19 #
    19 #
    20 # CDDL HEADER END
    20 # CDDL HEADER END
    21 #
    21 #
    22 # Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
    22 # Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved.
    23 #
    23 #
    24 #
    24 #
    25 # userland-fetch - a file download utility
    25 # userland-fetch - a file download utility
    26 #
    26 #
    27 #  A simple program similiar to wget(1), but handles local file copy, ignores
    27 #  A simple program similiar to wget(1), but handles local file copy, ignores
    79         if proc.returncode != 0:
    79         if proc.returncode != 0:
    80 		# Only print GnuPG's output when there was a problem.
    80 		# Only print GnuPG's output when there was a problem.
    81                 print proc.stdout.read()
    81                 print proc.stdout.read()
    82                 return False
    82                 return False
    83         return True
    83         return True
    84 	
    84 
    85 def validate(file, hash):
    85 def validate(file, hash):
    86 	"""Given a file-like object and a hash string, verify that the hash
    86 	"""Given a file-like object and a hash string, verify that the hash
    87 	matches the file contents."""
    87 	matches the file contents."""
    88 
    88 
    89 	try:
    89 	try:
   149 		printIOError(e, "Can't open archive " + filename)
   149 		printIOError(e, "Can't open archive " + filename)
   150 		return False
   150 		return False
   151 	return validate(file, hash)
   151 	return validate(file, hash)
   152 
   152 
   153 
   153 
   154 def download(url, filename=None, quiet=False):
   154 def download(url, timeout, filename=None, quiet=False):
   155 	"""Download the content at the given URL to the given filename
   155 	"""Download the content at the given URL to the given filename
   156 	(defaulting to the basename of the URL if not given.  If 'quiet' is
   156 	(defaulting to the basename of the URL if not given.  If 'quiet' is
   157 	True, throw away any error messages.  Returns the name of the file to
   157 	True, throw away any error messages.  Returns the name of the file to
   158 	which the content was donloaded."""
   158 	which the content was donloaded."""
   159 
   159 
   160 	src = None
   160 	src = None
   161 
   161 
   162 	try:
   162 	try:
   163 		src = urlopen(url)
   163 		src = urlopen(url=url, timeout=timeout)
   164 	except IOError as e:
   164 	except IOError as e:
   165 		if not quiet:
   165 		if not quiet:
   166 			printIOError(e, "Can't open url " + url)
   166 			printIOError(e, "Can't open url " + url)
   167 		return None
   167 		return None
   168 
   168 
   222 	if url != None and url not in urls:
   222 	if url != None and url not in urls:
   223 		urls.append(url)
   223 		urls.append(url)
   224 
   224 
   225 	return urls
   225 	return urls
   226 
   226 
   227 def download_from_paths(search_list, file_arg, url, link_arg, quiet=False):
   227 def download_from_paths(search_list, file_arg, url, timeout_arg, link_arg, quiet=False):
   228 	"""Attempts to download a file from a number of possible locations.
   228 	"""Attempts to download a file from a number of possible locations.
   229 	Generates a list of paths where the file ends up on the local
   229 	Generates a list of paths where the file ends up on the local
   230 	filesystem.  This is a generator because while a download might be
   230 	filesystem.  This is a generator because while a download might be
   231 	successful, the signature or hash may not validate, and the caller may
   231 	successful, the signature or hash may not validate, and the caller may
   232 	want to try again from the next location.  The 'link_arg' argument is a
   232 	want to try again from the next location.  The 'link_arg' argument is a
   256 						print "\n    linking..."
   256 						print "\n    linking..."
   257 					os.symlink(path, name)
   257 					os.symlink(path, name)
   258 		elif scheme in [ 'http', 'https', 'ftp' ]:
   258 		elif scheme in [ 'http', 'https', 'ftp' ]:
   259 			if not quiet:
   259 			if not quiet:
   260 				print "\n    downloading...",
   260 				print "\n    downloading...",
   261 			name = download(url, file_arg, quiet)
   261 			name = download(url, timeout_arg, file_arg, quiet)
   262 			if name == None:
   262 			if name == None:
   263 				if not quiet:
   263 				if not quiet:
   264 					print "failed"
   264 					print "failed"
   265 				continue
   265 				continue
   266 
   266 
   267 		yield name
   267 		yield name
   268 
   268 
   269 def usage():
   269 def usage():
   270 	print "Usage: %s [-f|--file (file)] [-l|--link] [-h|--hash (hash)] " \
   270 	print "Usage: %s [-f|--file (file)] [-l|--link] [-h|--hash (hash)] " \
   271           "[-s|--search (search-dir)] [-S|--sigurl (signature-url)] --url (url)" % \
   271           "[-s|--search (search-dir)] [-S|--sigurl (signature-url)] " \
       
   272 	  "[-t|--timeout (timeout)] --url (url)" % \
   272           (sys.argv[0].split('/')[-1])
   273           (sys.argv[0].split('/')[-1])
   273 	sys.exit(1)
   274 	sys.exit(1)
   274 
   275 
   275 def main():
   276 def main():
   276 	import getopt
   277 	import getopt
   277 
   278 
   278 	# FLUSH STDOUT 
   279 	# FLUSH STDOUT
   279 	sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)
   280 	sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)
   280 
   281 
   281 	file_arg = None
   282 	file_arg = None
   282 	link_arg = False
   283 	link_arg = False
   283 	hash_arg = None
   284 	hash_arg = None
   284 	url_arg = None
   285 	url_arg = None
   285 	sig_arg = None
   286 	sig_arg = None
       
   287 	timeout_arg = 300
   286 	search_list = list()
   288 	search_list = list()
   287 
   289 
   288 	try:
   290 	try:
   289                 opts, args = getopt.getopt(sys.argv[1:], "f:h:ls:S:u:",
   291                 opts, args = getopt.getopt(sys.argv[1:], "f:h:ls:S:t:u:",
   290 			["file=", "link", "hash=", "search=", "sigurl=", "url="])
   292 			["file=", "link", "hash=", "search=", "sigurl=",
       
   293 			"timeout=", "url="])
   291 	except getopt.GetoptError, err:
   294 	except getopt.GetoptError, err:
   292 		print str(err)
   295 		print str(err)
   293 		usage()
   296 		usage()
   294 
   297 
   295 	for opt, arg in opts:
   298 	for opt, arg in opts:
   301 			hash_arg = arg
   304 			hash_arg = arg
   302 		elif opt in [ "-s", "--search" ]:
   305 		elif opt in [ "-s", "--search" ]:
   303 			search_list.append(arg)
   306 			search_list.append(arg)
   304 		elif opt in [ "-S", "--sigurl" ]:
   307 		elif opt in [ "-S", "--sigurl" ]:
   305 			sig_arg = arg
   308 			sig_arg = arg
       
   309 		elif opt in [ "-t", "--timeout" ]:
       
   310 			try:
       
   311 				timeout_arg = int(arg)
       
   312 			except ValueError:
       
   313 				print "Invalid argument for %s, should be a " \
       
   314 				    "number, but is %s" % (opt, arg)
       
   315 				sys.exit(1)
       
   316 			if timeout_arg < 0:
       
   317 				print "Invalid argument for %s, should be a " \
       
   318 				    "positive number, but is %s" % (opt, arg)
       
   319 				sys.exit(1)
   306 		elif opt in [ "-u", "--url" ]:
   320 		elif opt in [ "-u", "--url" ]:
   307 			url_arg = arg
   321 			url_arg = arg
   308 		else:
   322 		else:
   309 			assert False, "unknown option"
   323 			assert False, "unknown option"
   310 
   324 
   311 	for name in download_from_paths(search_list, file_arg, url_arg, link_arg):
   325 	for name in download_from_paths(search_list, file_arg, url_arg,
       
   326 	    timeout_arg, link_arg):
   312 		print "\n    validating signature...",
   327 		print "\n    validating signature...",
   313 
   328 
   314 		sig_valid = False
   329 		sig_valid = False
   315 		if not sig_arg:
   330 		if not sig_arg:
   316 			print "skipping (no signature URL)"
   331 			print "skipping (no signature URL)"
   320 			sig_file = os.path.join(
   335 			sig_file = os.path.join(
   321 			    os.path.dirname(file_arg),
   336 			    os.path.dirname(file_arg),
   322 			    os.path.basename(sig_arg))
   337 			    os.path.basename(sig_arg))
   323 			# Validate with the first signature we find.
   338 			# Validate with the first signature we find.
   324 			for sig_file in download_from_paths(search_list, sig_file,
   339 			for sig_file in download_from_paths(search_list, sig_file,
   325 			    sig_arg, link_arg, True):
   340 			    sig_arg, timeout_arg, link_arg, True):
   326 				if sig_file:
   341 				if sig_file:
   327 					if validate_signature(name, sig_file):
   342 					if validate_signature(name, sig_file):
   328 						print "ok"
   343 						print "ok"
   329 						sig_valid = True
   344 						sig_valid = True
   330 					else:
   345 					else: