Files
metasploit-gs/tools/msftidy.rb
T

651 lines
19 KiB
Ruby
Raw Normal View History

2010-11-05 00:05:34 +00:00
#!/usr/bin/env ruby
# -*- coding: binary -*-
2010-11-05 00:05:34 +00:00
#
# Check (recursively) for style compliance violations and other
# tree inconsistencies.
#
2014-04-02 11:12:00 -05:00
# by jduck, todb, and friends
2010-11-05 00:05:34 +00:00
#
require 'fileutils'
require 'find'
2014-01-31 14:19:04 -06:00
require 'time'
2010-11-05 00:05:34 +00:00
2011-12-12 15:12:01 -06:00
CHECK_OLD_RUBIES = !!ENV['MSF_CHECK_OLD_RUBIES']
2014-06-12 13:46:10 -05:00
SUPPRESS_INFO_MESSAGES = !!ENV['MSF_SUPPRESS_INFO_MESSAGES']
2011-12-12 15:12:01 -06:00
if CHECK_OLD_RUBIES
2013-09-30 13:47:53 -05:00
require 'rvm'
warn "This is going to take a while, depending on the number of Rubies you have installed."
2011-12-12 15:12:01 -06:00
end
class String
2013-09-30 13:47:53 -05:00
def red
"\e[1;31;40m#{self}\e[0m"
end
2010-11-05 00:05:34 +00:00
2013-09-30 13:47:53 -05:00
def yellow
"\e[1;33;40m#{self}\e[0m"
end
2013-01-04 14:09:37 -06:00
def green
"\e[1;32;40m#{self}\e[0m"
end
2014-04-21 18:04:14 +02:00
def cyan
"\e[1;36;40m#{self}\e[0m"
end
2013-09-30 13:47:53 -05:00
def ascii_only?
self =~ Regexp.new('[\x00-\x08\x0b\x0c\x0e-\x19\x7f-\xff]', nil, 'n') ? false : true
end
2010-11-05 00:05:34 +00:00
end
class Msftidy
2011-12-12 15:12:01 -06:00
2014-01-31 14:19:04 -06:00
# Status codes
OK = 0x00
WARNINGS = 0x10
ERRORS = 0x20
attr_reader :full_filepath, :source, :stat, :name, :status
2013-09-30 13:47:53 -05:00
def initialize(source_file)
@full_filepath = source_file
2013-09-30 13:47:53 -05:00
@source = load_file(source_file)
2014-01-31 14:19:04 -06:00
@status = OK
@name = File.basename(source_file)
2013-09-30 13:47:53 -05:00
end
public
#
2014-01-31 14:19:04 -06:00
# Display a warning message, given some text and a number. Warnings
# are usually style issues that may be okay for people who aren't core
# Framework developers.
2013-09-30 13:47:53 -05:00
#
2014-01-31 14:19:04 -06:00
# @return status [Integer] Returns WARNINGS unless we already have an
# error.
def warn(txt, line=0) line_msg = (line>0) ? ":#{line}" : ''
2014-03-01 12:02:41 +01:00
puts "#{@full_filepath}#{line_msg} - [#{'WARNING'.yellow}] #{cleanup_text(txt)}"
2014-01-31 14:19:04 -06:00
@status == ERRORS ? @status = ERRORS : @status = WARNINGS
2013-09-30 13:47:53 -05:00
end
2014-01-31 14:19:04 -06:00
#
# Display an error message, given some text and a number. Errors
# can break things or are so egregiously bad, style-wise, that they
# really ought to be fixed.
#
# @return status [Integer] Returns ERRORS
2013-09-30 13:47:53 -05:00
def error(txt, line=0)
2014-01-23 14:21:48 -06:00
line_msg = (line>0) ? ":#{line}" : ''
2014-03-01 12:02:41 +01:00
puts "#{@full_filepath}#{line_msg} - [#{'ERROR'.red}] #{cleanup_text(txt)}"
2014-01-31 14:19:04 -06:00
@status = ERRORS
2013-09-30 13:47:53 -05:00
end
2014-01-31 14:19:04 -06:00
# Currently unused, but some day msftidy will fix errors for you.
def fixed(txt, line=0)
2014-01-23 14:21:48 -06:00
line_msg = (line>0) ? ":#{line}" : ''
2014-03-01 12:02:41 +01:00
puts "#{@full_filepath}#{line_msg} - [#{'FIXED'.green}] #{cleanup_text(txt)}"
end
2014-04-21 18:04:14 +02:00
#
# Display an info message. Info messages do not alter the exit status.
#
def info(txt, line=0)
2014-06-12 13:46:10 -05:00
return if SUPPRESS_INFO_MESSAGES
2014-04-21 18:04:14 +02:00
line_msg = (line>0) ? ":#{line}" : ''
puts "#{@full_filepath}#{line_msg} - [#{'INFO'.cyan}] #{cleanup_text(txt)}"
end
2013-09-30 13:47:53 -05:00
##
#
# The functions below are actually the ones checking the source code
#
##
2013-11-05 11:49:15 -06:00
def check_mode
unless (@stat.mode & 0111).zero?
warn("Module should not be marked executable")
end
end
2013-11-08 16:11:48 -06:00
def check_shebang
2013-11-20 15:26:35 -06:00
if @source.lines.first =~ /^#!/
2013-11-08 16:11:48 -06:00
warn("Module should not have a #! line")
end
end
2014-05-29 11:52:17 -05:00
# Updated this check to see if Nokogiri::XML.parse is being called
# specifically. The main reason for this concern is that some versions
# of libxml2 are still vulnerable to XXE attacks. REXML is safer (and
# slower) since it's pure ruby. Unfortunately, there is no pure Ruby
# HTML parser (except Hpricot which is abandonware) -- easy checks
# can avoid Nokogiri (most modules use regex anyway), but more complex
# checks tends to require Nokogiri for HTML element and value parsing.
2014-02-02 11:51:21 -06:00
def check_nokogiri
2014-05-29 11:52:17 -05:00
msg = "Using Nokogiri in modules can be risky, use REXML instead."
2014-02-02 11:51:21 -06:00
has_nokogiri = false
2014-05-29 11:52:17 -05:00
has_nokogiri_xml_parser = false
2014-02-02 11:51:21 -06:00
@source.each_line do |line|
2014-05-29 13:06:47 -05:00
if has_nokogiri
if line =~ /Nokogiri::XML\.parse/ or line =~ /Nokogiri::XML::Reader/
2014-05-29 11:52:17 -05:00
has_nokogiri_xml_parser = true
break
end
2014-05-29 13:06:47 -05:00
else
has_nokogiri = line_has_require?(line, 'nokogiri')
2014-02-02 11:51:21 -06:00
end
end
2014-05-29 11:52:17 -05:00
error(msg) if has_nokogiri_xml_parser
2014-02-02 11:51:21 -06:00
end
2013-09-30 13:47:53 -05:00
def check_ref_identifiers
in_super = false
in_refs = false
@source.each_line do |line|
2014-01-30 14:39:28 -06:00
if !in_super and line =~ /\s+super\(/
2013-09-30 13:47:53 -05:00
in_super = true
elsif in_super and line =~ /[[:space:]]*def \w+[\(\w+\)]*/
in_super = false
break
end
2014-01-08 20:32:30 -06:00
if in_super and line =~ /["']References["'][[:space:]]*=>/
2013-09-30 13:47:53 -05:00
in_refs = true
elsif in_super and in_refs and line =~ /^[[:space:]]+\],*/m
break
elsif in_super and in_refs and line =~ /[^#]+\[[[:space:]]*['"](.+)['"][[:space:]]*,[[:space:]]*['"](.+)['"][[:space:]]*\]/
identifier = $1.strip.upcase
value = $2.strip
case identifier
when 'CVE'
warn("Invalid CVE format: '#{value}'") if value !~ /^\d{4}\-\d{4}$/
when 'OSVDB'
warn("Invalid OSVDB format: '#{value}'") if value !~ /^\d+$/
when 'BID'
warn("Invalid BID format: '#{value}'") if value !~ /^\d+$/
when 'MSB'
warn("Invalid MSB format: '#{value}'") if value !~ /^MS\d+\-\d+$/
when 'MIL'
warn("milw0rm references are no longer supported.")
when 'EDB'
warn("Invalid EDB reference") if value !~ /^\d+$/
when 'WVE'
warn("Invalid WVE reference") if value !~ /^\d+\-\d+$/
when 'US-CERT-VU'
warn("Invalid US-CERT-VU reference") if value !~ /^\d+$/
2013-10-21 15:30:07 -05:00
when 'ZDI'
warn("Invalid ZDI reference") if value !~ /^\d{2}-\d{3}$/
2013-09-30 13:47:53 -05:00
when 'URL'
if value =~ /^http:\/\/www\.osvdb\.org/
warn("Please use 'OSVDB' for '#{value}'")
elsif value =~ /^http:\/\/cvedetails\.com\/cve/
warn("Please use 'CVE' for '#{value}'")
elsif value =~ /^http:\/\/www\.securityfocus\.com\/bid\//
warn("Please use 'BID' for '#{value}'")
elsif value =~ /^http:\/\/www\.microsoft\.com\/technet\/security\/bulletin\//
warn("Please use 'MSB' for '#{value}'")
elsif value =~ /^http:\/\/www\.exploit\-db\.com\/exploits\//
warn("Please use 'EDB' for '#{value}'")
elsif value =~ /^http:\/\/www\.wirelessve\.org\/entries\/show\/WVE\-/
warn("Please use 'WVE' for '#{value}'")
elsif value =~ /^http:\/\/www\.kb\.cert\.org\/vuls\/id\//
warn("Please use 'US-CERT-VU' for '#{value}'")
end
end
end
end
end
# See if 'require "rubygems"' or equivalent is used, and
# warn if so. Since Ruby 1.9 this has not been necessary and
# the framework only suports 1.9+
def check_rubygems
@source.each_line do |line|
if line_has_require?(line, 'rubygems')
warn("Explicitly requiring/loading rubygems is not necessary")
break
end
end
end
# Does the given line contain a require/load of the specified library?
def line_has_require?(line, lib)
line =~ /^\s*(require|load)\s+['"]#{lib}['"]/
end
2013-09-30 13:47:53 -05:00
def check_snake_case_filename
sep = File::SEPARATOR
good_name = Regexp.new "^[a-z0-9_#{sep}]+\.rb$"
unless @name =~ good_name
warn "Filenames should be alphanum and snake case."
end
end
2013-10-15 13:35:52 -05:00
def check_comment_splat
if @source =~ /^# This file is part of the Metasploit Framework and may be subject to/
2013-10-15 13:53:38 -05:00
warn("Module contains old license comment, use tools/dev/resplat.rb <filename>.")
2013-10-15 13:35:52 -05:00
end
end
2013-09-30 13:47:53 -05:00
def check_old_keywords
max_count = 10
counter = 0
if @source =~ /^##/
@source.each_line do |line|
# If exists, the $Id$ keyword should appear at the top of the code.
# If not (within the first 10 lines), then we assume there's no
# $Id$, and then bail.
break if counter >= max_count
if line =~ /^#[[:space:]]*\$Id\$/i
warn("Keyword $Id$ is no longer needed.")
break
end
counter += 1
end
end
2014-01-08 20:32:30 -06:00
if @source =~ /["']Version["'][[:space:]]*=>[[:space:]]*['"]\$Revision\$['"]/
2013-09-30 13:47:53 -05:00
warn("Keyword $Revision$ is no longer needed.")
end
end
def check_verbose_option
if @source =~ /Opt(Bool|String).new\([[:space:]]*('|")VERBOSE('|")[[:space:]]*,[[:space:]]*\[[[:space:]]*/
warn("VERBOSE Option is already part of advanced settings, no need to add it manually.")
end
end
def check_badchars
badchars = %Q|&<=>|
in_super = false
in_author = false
@source.each_line do |line|
#
# Mark our "super" code block
#
2014-01-30 14:39:28 -06:00
if !in_super and line =~ /\s+super\(/
2013-09-30 13:47:53 -05:00
in_super = true
elsif in_super and line =~ /[[:space:]]*def \w+[\(\w+\)]*/
in_super = false
break
end
#
# While in super() code block
#
2014-01-08 20:32:30 -06:00
if in_super and line =~ /["']Name["'][[:space:]]*=>[[:space:]]*['|"](.+)['|"]/
2013-09-30 13:47:53 -05:00
# Now we're checking the module titlee
mod_title = $1
mod_title.each_char do |c|
if badchars.include?(c)
error("'#{c}' is a bad character in module title.")
end
end
if not mod_title.ascii_only?
error("Please avoid unicode or non-printable characters in module title.")
end
# Since we're looking at the module title, this line clearly cannot be
# the author block, so no point to run more code below.
next
end
#
# Mark our 'Author' block
#
2014-01-08 20:32:30 -06:00
if in_super and !in_author and line =~ /["']Author["'][[:space:]]*=>/
2013-09-30 13:47:53 -05:00
in_author = true
elsif in_super and in_author and line =~ /\],*\n/ or line =~ /['"][[:print:]]*['"][[:space:]]*=>/
in_author = false
end
#
# While in 'Author' block, check for Twitter handles
#
if in_super and in_author
if line =~ /Author/
author_name = line.scan(/\[[[:space:]]*['"](.+)['"]/).flatten[-1] || ''
else
author_name = line.scan(/['"](.+)['"]/).flatten[-1] || ''
end
if author_name =~ /^@.+$/
error("No Twitter handles, please. Try leaving it in a comment instead.")
end
if not author_name.ascii_only?
error("Please avoid unicode or non-printable characters in Author")
end
end
end
end
def check_extname
if File.extname(@name) != '.rb'
error("Module should be a '.rb' file, or it won't load.")
end
end
2014-07-16 11:20:40 -05:00
# Explicitly skip this check if we're suppressing info messages
# anyway, since it takes a fair amount of time per module to perform.
def check_rubocop
2014-07-16 11:20:40 -05:00
return true if SUPPRESS_INFO_MESSAGES
out = %x{rubocop -n #{@full_filepath}}
ret = $?
2014-07-16 10:26:35 -05:00
info("Fails to pass Rubocop Ruby style guidelines (run 'rubocop #{@full_filepath}' to see violations)") unless ret.exitstatus == 0
end
def check_old_rubies
2013-09-30 13:47:53 -05:00
return true unless CHECK_OLD_RUBIES
return true unless Object.const_defined? :RVM
puts "Checking syntax for #{@name}."
2013-09-30 13:47:53 -05:00
rubies ||= RVM.list_strings
res = %x{rvm all do ruby -c #{@full_filepath}}.split("\n").select {|msg| msg =~ /Syntax OK/}
2013-09-30 13:47:53 -05:00
error("Fails alternate Ruby version check") if rubies.size != res.size
end
def check_ranking
return if @source !~ / \< Msf::Exploit/
available_ranks = [
'ManualRanking',
'LowRanking',
'AverageRanking',
'NormalRanking',
'GoodRanking',
'GreatRanking',
'ExcellentRanking'
]
if @source =~ /Rank \= (\w+)/
if not available_ranks.include?($1)
error("Invalid ranking. You have '#{$1}'")
end
end
end
def check_disclosure_date
2014-04-07 14:21:04 -05:00
return if @source =~ /Generic Payload Handler/
2013-09-30 13:47:53 -05:00
# Check disclosure date format
2014-01-08 20:32:30 -06:00
if @source =~ /["']DisclosureDate["'].*\=\>[\x0d\x20]*['\"](.+)['\"]/
2013-09-30 13:47:53 -05:00
d = $1 #Captured date
# Flag if overall format is wrong
if d =~ /^... \d{1,2}\,* \d{4}/
# Flag if month format is wrong
m = d.split[0]
months = [
'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'
]
error('Incorrect disclosure month format') if months.index(m).nil?
else
error('Incorrect disclosure date format')
end
else
2014-04-07 14:21:04 -05:00
error('Exploit is missing a disclosure date') if @source =~ / \< Msf::Exploit/
2013-09-30 13:47:53 -05:00
end
end
def check_title_casing
whitelist = %w{
2014-04-03 16:54:47 -05:00
a an and as at avserve callmenum configdir connect debug docbase dtspcd
execve file for from getinfo goaway gsad hetro historysearch htpasswd
ibstat id in inetd iseemedia jhot libxslt lmgrd lnk load main map
migrate mimencode multisort name net netcat nodeid ntpd nttrans of
on onreadystatechange or ovutil path pbot pfilez pgpass pingstr pls
popsubfolders prescan readvar relfile rev rexec rlogin rsh rsyslog sa
sadmind say sblistpack spamd sreplace tagprinter the to twikidraw udev
uplay user username via welcome with ypupdated zsudo
}
2014-01-08 20:32:30 -06:00
if @source =~ /["']Name["'][[:space:]]*=>[[:space:]]*['"](.+)['"],*$/
2013-09-30 13:47:53 -05:00
words = $1.split
words.each do |word|
if whitelist.include?(word)
2013-09-30 13:47:53 -05:00
next
elsif word =~ /^[a-z]+$/
warn("Suspect capitalization in module title: '#{word}'")
end
end
end
end
def check_bad_terms
# "Stack overflow" vs "Stack buffer overflow" - See explanation:
# http://blogs.technet.com/b/srd/archive/2009/01/28/stack-overflow-stack-exhaustion-not-the-same-as-stack-buffer-overflow.aspx
if @source =~ /class Metasploit\d < Msf::Exploit::Remote/ and @source.gsub("\n", "") =~ /stack[[:space:]]+overflow/i
warn('Contains "stack overflow" You mean "stack buffer overflow"?')
elsif @source =~ /class Metasploit\d < Msf::Auxiliary/ and @source.gsub("\n", "") =~ /stack[[:space:]]+overflow/i
warn('Contains "stack overflow" You mean "stack exhaustion"?')
end
end
def check_function_basics
functions = @source.scan(/def (\w+)\(*(.+)\)*/)
functions.each do |func_name, args|
# Check argument length
args_length = args.split(",").length
warn("Poorly designed argument list in '#{func_name}()'. Try a hash.") if args_length > 6
end
end
def check_lines
url_ok = true
no_stdio = true
in_comment = false
in_literal = false
src_ended = false
idx = 0
@source.each_line { |ln|
idx += 1
# block comment awareness
if ln =~ /^=end$/
in_comment = false
next
end
in_comment = true if ln =~ /^=begin$/
next if in_comment
# block string awareness (ignore indentation in these)
in_literal = false if ln =~ /^EOS$/
next if in_literal
in_literal = true if ln =~ /\<\<-EOS$/
# ignore stuff after an __END__ line
src_ended = true if ln =~ /^__END__$/
next if src_ended
if ln =~ /[\x00-\x08\x0b\x0c\x0e-\x19\x7f-\xff]/
error("Unicode detected: #{ln.inspect}", idx)
end
if ln =~ /[ \t]$/
warn("Spaces at EOL", idx)
end
2013-10-01 12:22:46 -05:00
# Check for mixed tab/spaces. Upgrade this to an error() soon.
2013-09-30 13:47:53 -05:00
if (ln.length > 1) and (ln =~ /^([\t ]*)/) and ($1.match(/\x20\x09|\x09\x20/))
warn("Space-Tab mixed indent: #{ln.inspect}", idx)
end
2013-10-01 12:22:46 -05:00
# Check for tabs. Upgrade this to an error() soon.
if (ln.length > 1) and (ln =~ /^\x09/)
warn("Tabbed indent: #{ln.inspect}", idx)
end
2013-09-30 13:47:53 -05:00
if ln =~ /\r$/
warn("Carriage return EOL", idx)
end
url_ok = false if ln =~ /\.com\/projects\/Framework/
if ln =~ /File\.open/ and ln =~ /[\"\'][arw]/
if not ln =~ /[\"\'][wra]\+?b\+?[\"\']/
warn("File.open without binary mode", idx)
end
end
if ln =~/^[ \t]*load[ \t]+[\x22\x27]/
error("Loading (not requiring) a file: #{ln.inspect}", idx)
end
# The rest of these only count if it's not a comment line
next if ln =~ /[[:space:]]*#/
2013-11-20 17:53:25 -06:00
if ln =~ /\$std(?:out|err)/i or ln =~ /[[:space:]]puts/
next if ln =~ /^[\s]*["][^"]+\$std(?:out|err)/
2013-09-30 13:47:53 -05:00
no_stdio = false
error("Writes to stdout", idx)
end
2014-05-21 16:18:36 -05:00
# You should not change datastore in code. For reasons. See
# RM#8498 for discussion, starting at comment #16:
#
# https://dev.metasploit.com/redmine/issues/8498#note-16
2013-09-30 13:47:53 -05:00
if ln =~ /(?<!\.)datastore\[["'][^"']+["']\]\s*=(?![=~>])/
2014-05-21 16:18:36 -05:00
info("datastore is modified in code: #{ln}", idx)
2013-09-30 13:47:53 -05:00
end
2014-05-12 21:23:30 +02:00
# do not read Set-Cookie header (ignore commented lines)
if ln =~ /^(?!\s*#).+\[['"]Set-Cookie['"]\]/i
warn("Do not read Set-Cookie header directly, use res.get_cookies instead: #{ln}", idx)
end
2014-03-28 22:43:53 +01:00
# Auxiliary modules do not have a rank attribute
if ln =~ /^\s*Rank\s*=\s*/ and @source =~ /<\sMsf::Auxiliary/
warn("Auxiliary modules have no 'Rank': #{ln}", idx)
end
2013-09-30 13:47:53 -05:00
}
end
2014-01-22 15:26:16 -06:00
def check_vuln_codes
checkcode = @source.scan(/(Exploit::)?CheckCode::(\w+)/).flatten[1]
if checkcode and checkcode !~ /^Unknown|Safe|Detected|Appears|Vulnerable|Unsupported$/
2014-01-23 14:21:48 -06:00
error("Unrecognized checkcode: #{checkcode}")
2014-01-22 15:26:16 -06:00
end
end
def check_vars_get
test = @source.scan(/send_request_cgi\s*\(\s*\{?\s*['"]uri['"]\s*=>\s*[^=})]*?\?[^,})]+/im)
2014-03-01 12:02:41 +01:00
unless test.empty?
test.each { |item|
info("Please use vars_get in send_request_cgi: #{item}")
2014-03-01 12:02:41 +01:00
}
end
end
2014-06-17 15:44:43 +02:00
def check_newline_eof
if @source !~ /(?:\r\n|\n)\z/m
info('Please add a newline at the end of the file')
end
end
2014-06-30 00:40:06 -05:00
def check_sock_get
if @source =~ /\s+sock\.get(\s*|\(|\d+\s*|\d+\s*,\d+\s*)/m && @source !~ /sock\.get_once/
info('Please use sock.get_once instead of sock.get')
end
end
def check_udp_sock_get
2014-07-14 14:36:08 -05:00
if @source =~ /udp_sock\.get/m && @source !~ /udp_sock\.get\([a-zA-Z0-9]+/
2014-06-30 00:40:06 -05:00
info('Please specify a timeout to udp_sock.get')
end
end
2013-09-30 13:47:53 -05:00
private
def load_file(file)
f = open(file, 'rb')
2013-11-05 11:49:15 -06:00
@stat = f.stat
buf = f.read(@stat.size)
2013-09-30 13:47:53 -05:00
f.close
return buf
end
2014-03-01 12:02:41 +01:00
def cleanup_text(txt)
# remove line breaks
txt = txt.gsub(/[\r\n]/, ' ')
# replace multiple spaces by one space
txt.gsub(/\s{2,}/, ' ')
end
end
2010-11-05 00:05:34 +00:00
2014-01-31 14:19:04 -06:00
#
# Run all the msftidy checks.
#
# @param full_filepath [String] The full file path to check
# @return status [Integer] A status code suitable for use as an exit status
def run_checks(full_filepath)
tidy = Msftidy.new(full_filepath)
2013-11-05 11:49:15 -06:00
tidy.check_mode
2013-11-08 16:11:48 -06:00
tidy.check_shebang
2014-02-02 11:51:21 -06:00
tidy.check_nokogiri
tidy.check_rubygems
2013-09-30 13:47:53 -05:00
tidy.check_ref_identifiers
tidy.check_old_keywords
tidy.check_verbose_option
tidy.check_badchars
tidy.check_extname
tidy.check_old_rubies
2013-09-30 13:47:53 -05:00
tidy.check_ranking
tidy.check_disclosure_date
tidy.check_title_casing
tidy.check_bad_terms
tidy.check_function_basics
tidy.check_lines
tidy.check_snake_case_filename
2013-10-15 13:35:52 -05:00
tidy.check_comment_splat
2014-01-22 15:26:16 -06:00
tidy.check_vuln_codes
tidy.check_vars_get
2014-06-17 15:44:43 +02:00
tidy.check_newline_eof
tidy.check_rubocop
2014-06-30 00:40:06 -05:00
tidy.check_sock_get
tidy.check_udp_sock_get
2014-01-31 14:19:04 -06:00
return tidy
end
2010-11-05 00:05:34 +00:00
##
#
# Main program
#
##
dirs = ARGV
2014-04-02 11:12:00 -05:00
@exit_status = 0
2014-01-31 14:19:04 -06:00
2014-04-02 11:12:00 -05:00
if dirs.length < 1
$stderr.puts "Usage: #{File.basename(__FILE__)} <directory or file>"
@exit_status = 1
exit(@exit_status)
2010-11-05 00:05:34 +00:00
end
dirs.each do |dir|
begin
Find.find(dir) do |full_filepath|
next if full_filepath =~ /\.git[\x5c\x2f]/
next unless File.file? full_filepath
next unless full_filepath =~ /\.rb$/
2014-01-31 14:19:04 -06:00
msftidy = run_checks(full_filepath)
@exit_status = msftidy.status if (msftidy.status > @exit_status.to_i)
end
rescue Errno::ENOENT
$stderr.puts "#{File.basename(__FILE__)}: #{dir}: No such file or directory"
2013-09-30 13:47:53 -05:00
end
end
2014-01-31 14:19:04 -06:00
exit(@exit_status.to_i)