#! /usr/bin/env python

# 3)  System Test
# 
#     Given a list of directories, report any bogus symbolic links contained
#     anywhere in those subtrees.  A bogus symbolic link is one that cannot
#     be resolved because it points to a nonexistent or otherwise
#     unresolvable file.  Do *not* use an external find executable.
#     Directories may be very very deep.  Print a warning immediately if the
#     system you're running on doesn't support symbolic links.

# This implementation:
# - takes one optional argument, using the current directory as default
# - uses chdir to increase performance
# - sorts the names per directory
# - prints output lines of the form "path1 -> path2" as it goes
# - prints error messages about directories it can't list or chdir into

import os
import sys
from stat import *

def main():
	try:
		# Note: can't test for presence of lstat -- it's always there
		dummy = os.readlink
	except AttributeError:
		print "This system doesn't have symbolic links"
		sys.exit(0)
	if sys.argv[1:]:
		prefix = sys.argv[1]
	else:
		prefix = ''
	if prefix:
		os.chdir(prefix)
		if prefix[-1:] != '/': prefix = prefix + '/'
		reportboguslinks(prefix)
	else:
		reportboguslinks('')

def reportboguslinks(prefix):
	try:
		names = os.listdir('.')
	except os.error, msg:
		print "%s%s: can't list: %s" % (prefix, '.', msg)
		return
	names.sort()
	for name in names:
		if name == os.curdir or name == os.pardir:
			continue
		try:
			mode = os.lstat(name)[ST_MODE]
		except os.error:
			print "%s%s: can't stat: %s" % (prefix, name, msg)
			continue
		if S_ISLNK(mode):
			try:
				os.stat(name)
			except os.error:
				print "%s%s -> %s" % \
				      (prefix, name, os.readlink(name))
		elif S_ISDIR(mode):
			try:
				os.chdir(name)
			except os.error, msg:
				print "%s%s: can't chdir: %s" % \
				      (prefix, name, msg)
				continue
			try:
				reportboguslinks(prefix + name + '/')
			finally:
				os.chdir('..')

main()
