#!/bin/sh # -------+---------+---------+-------- + --------+---------+---------+---------+ # / This first section is just a *safe* way to start up the ruby \ # | interpretter, without caring about the current setting of | # | PATH. This solves the problem of ruby being installed at | # | different locations on various operating systems. It would | # | much faster to use the new '/usr/bin/env -S-P' ability, but | # \ right now that is only on FreeBSD 6.x... Garance/2005 / OSRUBYBIN= for fname in /usr/local/bin /opt/csw/bin /opt/local/bin /usr/bin ; do if [ -x "$fname/ruby" ] ; then OSRUBYBIN="$fname/ruby" ; break; fi done if [ -z "$OSRUBYBIN" ] ; then echo "Unable to find a 'ruby' interpretter!" >&2 exit 1 fi # Set PATH to avoid warnings from ruby about writeable directories in PATH. # The value we set needs to be able to find 'fs' and 'vos'. PATH=/bin:/usr/bin:/opt/local/bin:/usr/local/bin:/sbin:/usr/sbin eval 'exec "$OSRUBYBIN" -x -S $0 ${1+"$@"}' echo "The 'exec \"$OSRUBYBIN\" -x -S ...' failed!" >&2 exit 1 #! This marker starts the real script: ruby # -------+---------+---------+-------- + --------+---------+---------+---------+ # Copyright (c) 2007 - Garance Alistair Drosehn . # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # # -------+---------+---------+-------- + --------+---------+---------+---------+ # $Id$ # -------+---------+---------+-------- + --------+---------+---------+---------+ # # Collecting info on the problem which keeps popping up with openafs # on MacOS 10.4. This might require ruby 1.8.5 (2006-08-25), which is # newer than what is included in 10.4 (I installed it via macports). # Garance/Mar 10/2007 # # -------+---------+---------+-------- + --------+---------+---------+---------+ # -------+---------+---------+-------- + --------+---------+---------+---------+ # Add a convenient method for converting a numeric value into a string # that includes commas as the "thousands" separator. Note that this # assumes the decimal separator (as returned by 'to_s') is always a # period, and the "thousands" separator we add is always a comma. # class Numeric def to_1000sep_s to_s.gsub(/(\d)(?=\d{3}+(?:\.|$))(\d{3}\..*)?/,'\1,\2') end end # -------+---------+---------+-------- + --------+---------+---------+---------+ require 'find' $debug_lvl = 0 auto_examine = false start_dir = nil # # These are some directories in cell rpi.edu where it's generally a bad # idea for this script to descend into. Note that entries in this array # need be appropriate as a regexp pattern. prune_dirs = Array.new prune_dirs << "rpi/anon-ftp" prune_dirs << "rpi/billing" prune_dirs << "samba/[^/]+/common" opterr = false ARGV.each { |arg| case arg when "--debug" $debug_lvl += 1 when /^--auto (?:-|_|) examine$/x auto_examine = true when /^--prune (?:-|_|) dir=(\S+.*)$/x prune_dirs << $1 when /^--start (?:-|_|) dir=(\S+.*)$/x start_dir = $1 if not File.exists?(start_dir) $stderr.printf "Error: --start-dir does not exist: %s\n", $1 opterr = true elsif not File.directory?(start_dir) $stderr.printf "Error: --start-dir is not a directory: %s\n", $1 opterr = true elsif start_dir[0..0] != "/" $stderr.printf "Error: --start-dir must be a fully-qualified directory\n" opterr = true end when /^-/ $stderr.printf "Invalid option: %s\n", arg opterr = true else $stderr.printf "Invalid argument: %s\n", arg opterr = true end } unless start_dir $stderr.printf "Error: You must specify --start-dir=pathane\n" opterr = true end if opterr $stderr.printf "Usage: #{File.basename($0)} [ --auto-examine ] --start-dir=somedir\n" $stderr.printf "where: 'somedir' should be a fully-qualifed path somewhere in /afs\n" exit 1 end start_time = Time.now.strftime("%T") $stderr.printf "Starting @ %s\n", start_time # The nature if the bug is that if we hit the bug, then we can't # call File.expand_path(). #if start_dir[0..0] != "/" # printf "--start-dir=%s\n", start_dir # start_dir = File.expand_path(start_dir) # printf " =%s\n", start_dir #end # Have to save this away, so we can 'cd' back to our starting point. # (since it might not be safe to call Dir.getwd here, either!) original_PWD = ENV["PWD"] dircount = 0 volcount = 0 skipped_links = Array.new bad_volumes = Hash.new volumes_seen = Hash.new(0) matchstart_re = Regexp.new( "^" + Regexp.escape(start_dir) + "/" ) prunedir_re = Regexp.new( "(" + prune_dirs.join("|") + ")" ) checkdir = nil begin Find.find(start_dir) { |testdir| checkdir = testdir if testdir == start_dir relname = ".../" + File.basename(start_dir) + " == start-dir" else relname = testdir.sub( matchstart_re, "") end if testdir =~ prunedir_re # Avoid going down these paths! printf " ... pruning %s\n", relname Find.prune end begin tstat = File.lstat(testdir) rescue # If we get an error here, the AFS volume really isn't there... printf "No AFS volume exists for %s\n", relname next end if tstat.symlink? begin tlink = File.readlink(testdir) if File.exists?(tlink) and File.directory?(tlink) skipped_links << testdir printf " ... skipping %s\n", testdir if $debug_lvl > 1 printf " link=> %s\n", tlink if $debug_lvl > 1 end rescue printf " ... skipping symlink %s\n", testdir if $debug_lvl > 1 end next end next unless tstat.directory? dircount += 1 # Print out a progress indicator every 1,250 lines, in case we # wander into a directory of infinite-depth. $stderr.printf " ... dir #%s = %s\n", dircount.to_1000sep_s, relname if 0 == dircount % 1250 vol_id = nil lq_out = IO.popen("/usr/bin/fs listquota '" + testdir + "'") lq_out.each { |qline| next if qline =~ /^Volume\s+ Name\s+ Quota\s+/x if qline =~ /^(\S+)\s+ \d+\s+ \d+\s+ \d+%<*\s+ \d+%<*/x vol_id = $1 end } lq_out.close lq_out = nil unless vol_id printf "-- No vol_id found in 'fs lq' for %s!\n", testdir next end seen_it = volumes_seen.has_key?(vol_id) volumes_seen[vol_id] += 1 next if seen_it printf "Found %-24s at %s\n", vol_id, relname if $debug_lvl > 0 volcount += 1 # Also nice to have some progress-indicator of how many AFS volumes # we've seen. $stderr.printf " ... AFS vol #%s = %s\n", volcount.to_1000sep_s, vol_id if 0 == volcount % 250 no_problem = true begin Dir.chdir testdir rescue SystemCallError printf " -- Dir.chdir(%s) failed: %s\n", testdir, $! no_problem = false end if no_problem begin workdir = Dir.getwd rescue SystemCallError printf " -- Error from Dir.getwd: %s\n", $! printf " after Dir.chdir to: %s\n", testdir no_problem = false end end begin Dir.chdir original_PWD rescue SystemCallError printf " -- Dir.chdir back to %s failed: %s\n", testdir, $! no_problem = false end next if no_problem bad_volumes[testdir] = vol_id } rescue Interrupt # If an interrupt occurs during that find-processing, then just print # a newline and finish off with the statistics we have so far. $stderr.printf "\n ... interrupt received while checking:\n %s\n", checkdir end $stderr.printf "\nDone @ %s (started @ %s)\n", Time.now.strftime("%T"), start_time if dircount < 1 $stderr.printf "No directories found!\n" exit 0 end $stderr.printf "Checked %d directories", dircount if skipped_links.length > 0 $stderr.printf " (skipped %d links to other directories)", skipped_links.length end $stderr.printf ".\n" if volcount < 1 $stderr.printf "No AFS volumes found at --start-dir=%s\n", start_dir exit 0 end $stderr.printf "Found %d AFS volumes", volcount if bad_volumes.length > 0 $stderr.printf ", and had getwd() problems with %d of them", bad_volumes.length else $stderr.printf ", and none had problems with getwd()" end $stderr.printf ".\n" if bad_volumes.length > 0 if auto_examine printf "\n = = = = = = = = = = = = = = = = = = = = = = = = = = = = =\n" else printf "\n" printf " %-26s %s\n", "Volume name", "Directory" printf " %-26s %s\n", "___________", "_________" end bad_volumes.keys.sort.each { |testdir| vol_id = bad_volumes[testdir] if testdir == start_dir relname = ".../" + File.basename(start_dir) + " == start-dir" else relname = testdir.sub( matchstart_re, "") end if auto_examine printf " = = 'fs la' and 'vos examine' for %s:\n", relname system("/usr/bin/fs listacl '" + testdir + "'") system("/usr/sbin/vos examine '" + vol_id + "'") printf "\n" else printf " %-26s %s\n", vol_id, relname end } printf "\n" unless auto_examine end exit 0